API Stability Notice

Macroforge is under active development. The API is not yet stable and may change between versions. Some documentation sections may be outdated.

Ord

The Ord macro generates a compareTo() method for total ordering comparison. This is analogous to Rust’s Ord trait, enabling objects to be sorted and compared with a guaranteed ordering relationship.

Generated Output

TypeGenerated CodeDescription
ClassclassNameCompare(a, b) + static compareTo(a, b)Standalone function + static wrapper method
EnumenumNameCompare(a: EnumName, b: EnumName): numberStandalone function comparing enum values
InterfaceinterfaceNameCompare(a: InterfaceName, b: InterfaceName): numberStandalone function comparing fields
Type AliastypeNameCompare(a: TypeName, b: TypeName): numberStandalone function with type-appropriate comparison

Return Values

Unlike PartialOrd, Ord provides total ordering - every pair of values can be compared:

  • -1: a is less than b
  • 0: a is equal to b
  • 1: a is greater than b

The function never returns null - all values must be comparable.

Comparison Strategy

Fields are compared lexicographically in declaration order:

  1. Compare first field
  2. If not equal, return that result
  3. Otherwise, compare next field
  4. Continue until a difference is found or all fields are equal

Type-Specific Comparisons

TypeComparison Method
number/bigintDirect < and > comparison
stringlocaleCompare() (clamped to -1, 0, 1)
booleanfalse < true
ArraysLexicographic element-by-element
DategetTime() timestamp comparison
ObjectsCalls compareTo() if available, else 0

Field-Level Options

The @ord decorator supports:

  • skip - Exclude the field from ordering comparison

Example

Before (Your Code)
/** @derive(Ord) */
class Version {
    major: number;
    minor: number;
    patch: number;
}
After (Generated)
class Version {
    major: number;
    minor: number;
    patch: number;

    static compareTo(a: Version, b: Version): number {
        return versionCompare(a, b);
    }
}

export function versionCompare(a: Version, b: Version): number {
    if (a === b) return 0;
    const cmp0 = a.major < b.major ? -1 : a.major > b.major ? 1 : 0;
    if (cmp0 !== 0) return cmp0;
    const cmp1 = a.minor < b.minor ? -1 : a.minor > b.minor ? 1 : 0;
    if (cmp1 !== 0) return cmp1;
    const cmp2 = a.patch < b.patch ? -1 : a.patch > b.patch ? 1 : 0;
    if (cmp2 !== 0) return cmp2;
    return 0;
}

Generated output:

class Version {
    major: number;
    minor: number;
    patch: number;

    static compareTo(a: Version, b: Version): number {
        return versionCompare(a, b);
    }
}

export function versionCompare(a: Version, b: Version): number {
    if (a === b) return 0;
    const cmp0 = a.major < b.major ? -1 : a.major > b.major ? 1 : 0;
    if (cmp0 !== 0) return cmp0;
    const cmp1 = a.minor < b.minor ? -1 : a.minor > b.minor ? 1 : 0;
    if (cmp1 !== 0) return cmp1;
    const cmp2 = a.patch < b.patch ? -1 : a.patch > b.patch ? 1 : 0;
    if (cmp2 !== 0) return cmp2;
    return 0;
}

Ord vs PartialOrd

  • Use Ord when all values are comparable (total ordering)
  • Use PartialOrd when some values may be incomparable (returns Option<number>)