Why can't my subclass declare only '==' when its super class has '<=>' (E07186)?
← Operators and Expressions · Ref: Q2244
Below an ORDERED type - a super class with '<=>' - a subtype that declares its own sameness must declare '<=>', by hand or with 'default operator <=>'; '==' alone is E07186.
With '==' alone the subtype would answer two questions differently: its own '==' compares all its fields, while the '<=>' it inherits compares only the super's. Two Named values with the same count and different names would be different by '==' and the same by '<=>' - so a sort, '<' or '<?' would treat them as one.
With '<=>' declared, 'default operator <=>' compares the super's '<=>' first and then the subtype's own fields, and '==' '<>' '<' '<=' '>' '>=' are generated from it, so they always agree. Below an equatable-only super (one with '==' and no '<=>') '==' alone is right. A bare 'default operator' gives '<=>' below an ordered super only where every field of the subtype can be ordered; a field with no '<=>' (a Dict or a List) makes it E07186 too, naming the field - hold the super in a field instead of extending it, or write '<=>' by hand. Below an equatable-only super it gives '==' (and '#?'). A subtype that adds fields must declare its own sameness one of these ways - declaring none is E07238 (Q2248).
Example
#!ek9 defines module qa.operators.ordered.super.needs.ordering defines constant firstName <- "ada" secondName <- "bob" defines class //An ordered type: the bare 'default operator' gives it '<=>' over count. Holder as open count as Integer: 1 Holder() -> start as Integer this.count: start default operator Named extends Holder name as String: String() Named() -> start as Integer label as String super(start) this.name: label //'<=>' compares Holder's count first, then name; '==' and the rest are generated from it. default operator <=> default operator ? default operator $ default operator $$ default operator :=: default operator #? //Every field of Badge can be ordered, so its bare 'default operator' keeps it ordered below Holder. Badge extends Holder tier as String: "gold" Badge() -> start as Integer super(start) default operator defines function flag() -> answer as Boolean <- rtn as String: answer? <- $answer else "unset" defines program OrderedSuperNeedsOrdering() stdout <- Stdout() ada <- Named(1, firstName) bob <- Named(1, secondName) stdout.println(`Named(1, ada) == Named(1, bob): ${flag(ada == bob)}`) stdout.println(`Named(1, ada) < Named(1, bob): ${flag(ada < bob)}`) sorted <- List() of Named cat [Named(2, firstName), bob, ada] | sort > sorted stdout.println(`sorted: ${sorted}`) lowBadge <- Badge(1) highBadge <- Badge(2) stdout.println(`Badge(1) < Badge(2): ${flag(lowBadge < highBadge)}`)
Common mistakes
E07186 — Holder is ordered, so Named's own sameness must be '<=>': the '<=>' Named would otherwise inherit compares only count and would disagree with a '==' over count and name. See ek9 -h E07186.
Incorrect:
default operator ==
Correct:
default operator <=>
E07186 — A Dict has no '<=>', so Badge's bare 'default operator' cannot give Badge a '<=>' and Badge would be equatable only while Holder is ordered. Keep every field orderable, write '<=>' by hand, or hold a Holder in a field instead of extending it. See ek9 -h E07186.
Incorrect:
tier as Dict of (String, String): Dict() of (String, String)
Correct:
tier as String: "gold"
Other ways to ask this
- What does E07186 mean?
- Why must a subtype of an ordered type declare '<=>'?
- Why is 'default operator ==' rejected on a class that extends a class with 'default operator'?
- How does a subclass that adds a field keep its ordering consistent with its equality?
Coming from another language?
Java: a subclass that overrides equals but inherits compareTo is 'inconsistent with equals' - the Comparable javadoc warns that a TreeSet or TreeMap then behaves strangely, and nothing stops it. EK9 makes that inconsistency a compile error: a subtype of an ordered type extends the ordering, and equality is generated from it.
Keywords: <=>, ==, E07186, consistent with equals, default operator, ordering, sameness, subclass