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
| Type | Generated Code | Description |
|---|---|---|
| Class | classNamePartialCompare(a, b) + static partialCompare(a, b) | Standalone function + static wrapper method |
| Enum | enumNamePartialCompare(a, b): number \| null | Standalone function returning number \| null |
| Interface | ifaceNamePartialCompare(a, b): number \| null | Standalone function returning number \| null |
| Type Alias | typeNamePartialCompare(a, b): number \| null | Standalone 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:
ais less thanb - 0:
ais equal tob - positive:
ais greater thanb - 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:
- Compare first field
- If incomparable, return
null - If not equal, return that result
- Otherwise, compare next field
- Continue until a difference is found or all fields are equal
Type-Specific Comparisons
| Type | Comparison Method |
|---|---|
number | < and >; null when either is NaN |
bigint, string | < and >, strings by UTF-16 code units |
boolean | false < true |
| Optional and nullable | An absent value orders first |
| Arrays | Lexicographic, each element by its own type; null on an unordered element |
Date | Timestamp; null if invalid |
Types deriving PartialOrd | Their partialCompare function |
| Anything else | structuralCompare 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
/** @derive(PartialEq, PartialOrd) */
class Temperature {
value: number;
unit: string;
}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.