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 compareTo() method for partial ordering comparison. This is analogous to Rust’s PartialOrd trait, enabling comparison between values where some pairs may be incomparable.

Generated Output

TypeGenerated CodeDescription
ClassclassNamePartialCompare(a, b) + static compareTo(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., TemperaturetemperaturePartialCompare).

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

Note: results are not clamped to -1/0/1. String fields return the raw localeCompare() value, which can be any negative or positive number (unlike Ord, which clamps localeCompare results). Only check the sign of the result.

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/bigintTernary comparison (a < b ? -1 : a > b ? 1 : 0)
stringlocaleCompare() (raw, unclamped result)
booleanfalse < true (cast to number)
null/undefinedReturns null for mismatched nullability
ArraysLexicographic, propagates null on incomparable elements
DateTimestamp comparison, null if invalid
ObjectsDelegates to compareTo() if available

Field-Level Options

The @ord decorator supports:

  • skip - Exclude the field from ordering comparison

Example

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

    static compareTo(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 = (() => {
        if (typeof (a.value as any)?.compareTo === 'function') {
            const optResult = (a.value as any).compareTo(b.value);
            return optResult === null ? null : optResult;
        }
        return a.value === b.value ? 0 : null;
    })();
    if (cmp0 === null) return null;
    if (cmp0 !== 0) return cmp0;
    const cmp1 = a.unit.localeCompare(b.unit);
    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.