E07181: comparisons with the type itself are generated from its sameness ('<=>' or '=='), never written or requested
What went wrong
A comparison of this type with ITSELF is written by hand, or asked for with an explicit 'default operator', but it is always generated from the type's sameness:
from '<=>': == <> < <= > >= ('==' is (a <=> b) == 0) from '==': <> (an equatable-only type has no ordering)
"Itself" includes any type this type is assignable to - a super, a trait, Any - so '==(Any)' or 'override ==(Base)' is a self-comparison too.
EK9 codifies Java's equals/hashCode/compareTo contract (Effective Java items 10, 11 and 14) as a compile error: a type defines its SAMENESS once - '<=>' if it is ordered, '==' if it is equatable only - and every other comparison is generated from it, so two ways of saying "equal" cannot disagree.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 1402 (How do I define equality and ordering for my own type?)
How to fix it
- Delete the operator (or the 'default operator <' line): it is generated.
- If a hand '==' compared MORE fields than '<=>', extend '<=>' with those fields as tie-breakers, so the generated '==' gives the same answers.
- For ANOTHER ordering ("sort by age"), write a comparator function and use 'sort by byAge' - never a second '<=>'.
- An operator taking an UNRELATED type ('==(Integer)', '<(Date)') is allowed.
Common causes
- Porting a Java/C# class that implements equals and compareTo separately
- A '<' or '==' that quietly compared different fields from '<=>'
- 'default operator <' lines that were needed before comparisons were generated
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E07181: comparisons with the type itself are generated from its sameness ('<=>' or '=='), never written or requested
#!ek9 defines module error.e07181.bad defines class Person id as Integer? default private Person() Person() -> identifier as Integer this.id: identifier identity() as pure <- rtn as Integer: id operator <=> as pure -> other as Person <- rtn as Integer: id <=> other.identity() operator < as pure -> other as Person <- rtn as Boolean: id < other.identity() override operator ? as pure <- rtn as Boolean: id? //'<' is generated from '<=>' - it is never written operator #? as pure <- rtn as Integer: #?id
Fixed: Delete it: '<' and the other comparisons come from '<=>'
#!ek9 defines module error.e07181.good.fix defines class Person id as Integer? default private Person() Person() -> identifier as Integer this.id: identifier identity() as pure <- rtn as Integer: id operator <=> as pure -> other as Person <- rtn as Integer: id <=> other.identity() override operator ? as pure <- rtn as Boolean: id? //'<' is generated from '<=>' - it is never written operator #? as pure <- rtn as Integer: #?id
Fixed: Delete it: it is generated from the sameness operator
#!ek9 defines module error.e07181.good defines class Person id as Integer? default private Person() Person() -> identifier as Integer this.id: identifier identity() as pure <- rtn as Integer: id //'<' '<=' '>' '>=' '==' '<>' are all generated from this operator <=> as pure -> other as Person <- rtn as Integer: id <=> other.identity() operator #? as pure <- rtn as Integer: #?id override operator ? as pure <- rtn as Boolean: id? defines program ComparePeople() stdout <- Stdout() first <- Person(1) second <- Person(2) stdout.println(`first < second: ${first < second}`)
Questions and answers
These Q&A entries show E07181 and its fix:
- Q1049: How do I implement comparison operators on a record for sorting?
- Q1055: Should I write #? and $ manually or use default operator?
- Q1065: Write an EK9 class with comparison operators so I can sort a list of them.
- Q1320: Why can't I declare 'operator !=' on my EK9 type?
- Q1398: How are defaulted comparison operators derived - does a defaulted == agree with my <=>?
- Q1402: How do I define equality and ordering for my own type, and why can't I write '==' beside '<=>'?