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.

PartialOrd

The PartialOrd macro generates a partialCompare() method for partial ordering comparison. This is analogous to Rust’s PartialOrd trait, enabling comparison between values where some pairs may be incomparable. Like partial_cmp and cmp in Rust, it sits beside Ord’s compare() without colliding.

Generated Output

TypeGenerated CodeDescription
ClassclassNamePartialCompare(a, b) + static partialCompare(a, b)Standalone function + static wrapper method
EnumenumNamePartialCompare(a, b): number \| nullStandalone function returning number \| null
InterfaceifaceNamePartialCompare(a, b): number \| nullStandalone function returning number \| null
Type AliastypeNamePartialCompare(a, b): number \| nullStandalone function returning number \| null

Names use camelCase conversion (e.g., Temperature → temperaturePartialCompare).

Return Values

Unlike Ord, PartialOrd returns number | null to handle incomparable values:

  • negative: a is less than b
  • 0: a is equal to b
  • positive: a is greater than b
  • null: Values are incomparable

A comparison is 0 exactly when the derived PartialEq holds. Strings therefore order by UTF-16 code units, not localeCompare, which can call distinct strings equal.

When to Use PartialOrd vs Ord

  • PartialOrd: When some values may not be comparable

    • Example: Floating-point NaN values
    • Example: Mixed-type unions
    • Example: Type mismatches between objects
  • Ord: When all values are guaranteed comparable (total ordering)

Comparison Strategy

Fields are compared lexicographically in declaration order:

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

Type-Specific Comparisons

TypeComparison Method
number< and >; null when either is NaN
bigint, string< and >, strings by UTF-16 code units
booleanfalse < true
Optional and nullableAn absent value orders first
ArraysLexicographic, each element by its own type; null on an unordered element
DateTimestamp; null if invalid
Types deriving PartialOrdTheir partialCompare function
Anything elsestructuralCompare from @macroforge/core/structural

Requirements

PartialOrd requires PartialEq, as in Rust. Deriving it without PartialEq is an expansion error.

Field-Level Options

The @ord decorator supports:

  • skip - Exclude the field from ordering comparison

Example

Before (Your Code)
/** @derive(PartialEq, PartialOrd) */
class Temperature {
    value: number;
    unit: string;
}
After (Generated)
class Temperature {
    value: number;
    unit: string;

    static partialCompare(a: Temperature, b: Temperature): number | null {
        return temperaturePartialCompare(a, b);
    }
}

export function temperaturePartialCompare(a: Temperature, b: Temperature): number | null {
    if (a === b) return 0;
    const cmp0 = a.value < b.value ? -1 : a.value > b.value ? 1 : a.value === b.value ? 0 : null;
    if (cmp0 === null) return null;
    if (cmp0 !== 0) return cmp0;
    const cmp1 = a.unit < b.unit ? -1 : a.unit > b.unit ? 1 : 0;
    if (cmp1 === null) return null;
    if (cmp1 !== 0) return cmp1;
    return 0;
}

Return Type

The generated functions return number | null where null indicates incomparable values.