Object
Object is the universal root class. Every class you write without an explicit
parent (every class X { … }) inherits from it implicitly. Its protocol
methods are the defaults your own types get, and the ones a
Map, Set or
Array uses when you don’t override them. It also
gives every object its class name at run time, and makes an instance from a
class name.
#import "Foundation.xc" // Object comes in with the umbrellaOverview
Section titled “Overview”You write nothing to inherit from Object: it is the implicit parent of any
parentless class. An Object* accepts a pointer to any class you define, and
any of your instances fits wherever an Object* is expected.
Its defaults are the cheapest correct implementations:
equalsis pointer identity: twoObject*s are equal only when they point at the same heap block.hashfolds the receiver’s address. Distinct instances live at distinct addresses, so they always hash apart.descriptionreturns the placeholder<Object>.encodeWithCoderandinitWithCoderarchive nothing.
The pointer hash is not cached on the instance. It takes two instructions,
so a one-byte cache field on every object in the program would cost more memory
than it saves in cycles. A class whose hash is expensive (a long
String) can cache it in a private ivar of its own.
Override equals and hash together when your class
needs value semantics rather than identity. Number
compares by stored numeric value; String and
Data fold over their bytes. The default hash is
address-derived and varies between runs, which is why
Map and Set iterate in insertion
order rather than hash order.
Conforms to
Section titled “Conforms to”Hashable:hashmakes any object usable as aMap/Setkey.Comparable:equalsis the required slot. The optionalcompareis not implemented (identity has no natural order), so plainObjects have equality but no ordering.Codable: the emptyencodeWithCoder/initWithCoderpair, so any object can be given to aCoder. Not on xt6502, whereObjecthas only the three methods above.
Every class is an Object, so every class has these protocol vtables and
defaults from the moment it is declared.
Topics
Section titled “Topics”Protocol methods · equals · hash · description · encodeWithCoder / initWithCoder
Class names · className · newInstanceOfClass
Protocol methods
Section titled “Protocol methods”The hooks your classes inherit and override.
equals
Section titled “equals”bool equals(Object* other)Pointer identity: true only when self and other are the same heap block.
This is the Comparable / Hashable
equals slot, dispatched through the vtable every object carries. Override it
(together with hash) to give your class value semantics.
u32 hash(void) // u8 on the xt6502 buildAn XOR-and-multiply scramble of the receiver’s address (a plain XOR-fold of the
low address bytes on the 6502). Distinct instances live at distinct heap
addresses, so they always hash apart. This is the
Hashable method, so any object can key a
Map or Set with no extra work.
It is not cached; see Overview.
description
Section titled “description”String* description(void)A String describing the object. The default returns
the placeholder <Object>. Stdio.printf’s %@ conversion dispatches through
this hook, so overriding it controls how your class prints: a
Number renders its value, and a
Data renders <Data 4: deadbeef>.
encodeWithCoder / initWithCoder
Section titled “encodeWithCoder / initWithCoder”void encodeWithCoder(Coder* coder)void initWithCoder(Coder* coder)The Codable pair, empty here. A class with state to
archive overrides both and calls super first, so every level of a hierarchy
codes its own fields; see Codable for an example.
Not present on xt6502.
Class names
Section titled “Class names”The name of an object’s class at run time, and an instance made from a name.
A keyed archiver uses the pair: it writes className() beside each object’s
fields, and reads the object back with newInstanceOfClass.
Object* o = new Circle();Stdio.printf("%s\n", o.className().cString()); // Circle
Object* c = Object.newInstanceOfClass(String.withCString("Circle"));className
Section titled “className”final String* className(void)The name of the receiver’s class as written in its source: "Circle" for a
Circle, even when you hold it as an Object* or as a pointer to one of its
parents. The result is a new String that the caller
owns. className is final: a class cannot override it.
It works for an instance whose class came from another module, a -c object
or an --emit-lib library, because each module records the names of the
classes it defines. It returns null for an instance of a class built by an
older compiler, which recorded no names.
newInstanceOfClass
Section titled “newInstanceOfClass”static Object* newInstanceOfClass(String* name)A new instance of the class called name, made as new C() makes one: it
comes back with a reference count of 1, owned by the caller, and the class’s
zero-argument init runs, after its parents’ inits as usual. A class that
declares only inits with parameters comes back zero-filled with no init
run, as new C() does for it. Returns null when name is null or no class of
that name can be found.
The search covers the classes of the module that holds main (or, called from
inside a library, the library’s own classes), and then every module it
imports, and every module those import, in import order. A class in a -c
object or an --emit-lib library is found when the program #imports that
module. A library cannot find a class that only its client defines.
A program that uses neither method and imports no module pays a few dozen
bytes at most. A library, a -c object, or a program that imports one carries
a small table: one name function per class, and one function that makes each
class by name.