Class DefaultedComparisonDelegate

java.lang.Object
org.ek9lang.compiler.support.DefaultedComparisonDelegate

public final class DefaultedComparisonDelegate extends Object
THE decision of which operator a GENERATED comparison is answered by - call this, do not re-derive it.

A defaulted < <= > >= is <=> against zero. A defaulted == is <=> when the type has its own comparator, otherwise field by field. A defaulted <> is <=> when the type has its own comparator and no hand-written ==, otherwise the negation of ==.

Two parts of the compiler must answer this identically: synthesis (SyntheticOperatorGenerator), which emits the delegating call, and the phase-5 call graph, which must hold the same edge - without it an assert in a <=> reached only through a generated < was reported orphaned (E81011) instead of reached from production (E81012) (B18 prerequisite P3). Extracted 2026-09-30 from SyntheticOperatorGenerator's private predicates so they cannot drift; B18 reshapes these rules here, once.

  • Method Details

    • of

      public static Optional<MethodSymbol> of(IAggregateSymbol aggregate, MethodSymbol operator, ISymbol ek9Any)
      The operator a generated comparison delegates to, resolved on the type (its own, a super's or a trait's). Empty when the operator is not a generated comparison, or it is compared field by field (a defaulted == with no comparator) and so delegates to no single operator of this type.
    • forAggregate

      public static DefaultedComparisonDelegate.Resolver forAggregate(IAggregateSymbol aggregate, ISymbol ek9Any)
      of(IAggregateSymbol, MethodSymbol, ISymbol) for the operators of ONE aggregate, for a caller that asks about each of them in turn: the type's facts - whether it has its own comparator or a hand-written ==, and which <=> and == serve it - are worked out at most once, not once per operator. The same decision as of(IAggregateSymbol, MethodSymbol, ISymbol), which uses it. Holds answers about the type as it is now, so use it while nothing is being defined into the type.
    • hasOwnComparator

      public static boolean hasOwnComparator(IAggregateSymbol aggregate, ISymbol ek9Any)
      True when the aggregate has its own REAL <=> that takes itself - hand-written, or defaulted (and not retracted) over fields that can all really be ordered. Then every defaulted comparison, == and <> included, is answered by it (Steve, 2026-09-29), so a defaulted operator can never disagree with the type's ordering. Without one, == is field by field and <> its negation.

      🔑 A defaulted <=> over a field that cannot be ordered degenerates to Any's, which is UNSET: a generic Box of List derived an UNSET == from it while field by field is true (Fable review p05d). So such an instantiation falls back to field-wise == - B07's rule applied per instantiation (B18 rule 8).

    • hasHandWrittenEquality

      public static boolean hasHandWrittenEquality(IAggregateSymbol aggregate)
      True when the developer wrote an == that takes the type itself (not a defaulted one). A hand-written == is the type's equality, so the defaulted <> is its negation - even beside a <=>, or the two would disagree. INTERIM: B18 makes a hand-written comparison beside a <=> an error.