Skip to content

Comparable

Comparable is the protocol a class adopts to be compared by value rather than by pointer identity. Equality is required; a total ordering is optional.

class MyType <Comparable> { ... }

By default, two Object* references are equal only when they are the same pointer. For value-like data, such as two Numbers holding 42 or two Strings spelling "go", you usually want value equality. Conforming to Comparable lets a class define when two of its instances are equal, so instances can be stored in the value-comparing collections (Array, Map, Set) and found by content instead of by address.

A class that also implements the optional compare has a total ordering: it is sortable (Array.sort) and can be used wherever the library needs an order.

Topics · equals · compare

bool equals(Object* other);

The only required method. Return true when self and other hold the same value. other is an arbitrary Object*, so a conformer starts with a safe-checked downcast and returns false for a mismatch:

bool equals(Object* other) {
MyType* o = (MyType* ?)other; // null if the kinds differ
if (o == 0) return false;
return /* self vs o, by value */;
}

A class may also provide a same-kind fast path, equals(MyType* other). The overload resolver picks the typed version when the argument’s static type is known and uses the Object* slot otherwise, so one protocol slot serves both.

↑ Topics

optional i8 compare(Object* other);

Optional. Returns the C / Foundation three-way convention:

returnmeaningFoundation
< 0self sorts before otherNSOrderedAscending
0they sort equallyNSOrderedSame
> 0self sorts after otherNSOrderedDescending

It is optional because every value can be tested for equality but not every value has an order: a colour or a network packet can be compared for sameness without one being “less than” another. A class that omits compare has no order.

An unimplemented optional method leaves a NULL vtable slot, which is what respondsTo tests:

callback f i8(Object* o) = &obj.compare; // null when the class doesn't implement it
if (f) { /* it has an order */ }

Array.sort uses that test and returns false for elements that define no order. To order values that are not Comparable-ordered, pass sortUsing() a comparator.

The protocol header has a typedef for the bound-method type:

typedef i8 cmp1_t(Object*); // the type of &obj.compare

↑ Topics

Standard-library classes that conform:

  • Object: the root declares <Hashable, Comparable> and supplies identity-based equals/hash, but does not implement compare. A concrete subclass that needs ordering provides its own, as the value classes below do.
  • String: lexicographic by unsigned byte, then by length.
  • Number: numeric ordering.
  • Data: byte-wise ordering.

See also the sibling protocols Hashable and Copying.

Conform to Comparable when instances need to be sorted or keyed by value. A Map or Set key must conform to both Comparable (to break ties inside a bucket’s probe chain) and Hashable (to find the bucket). The two are independent, so a value that only needs to be found or sorted, and is never hashed, can adopt Comparable alone.