E07181: comparisons with the type itself are generated from its sameness ('<=>' or '=='), never written or requested

Category: E07xxx Full resolution · Reported in phase: FULL_RESOLUTION · Classification: COMPARISON_GENERATED_FROM_SAMENESS · All error codes

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

  1. Delete the operator (or the 'default operator <' line): it is generated.
  2. If a hand '==' compared MORE fields than '<=>', extend '<=>' with those fields as tie-breakers, so the generated '==' gives the same answers.
  3. For ANOTHER ordering ("sort by age"), write a comparator function and use 'sort by byAge' - never a second '<=>'.
  4. 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

  • E07182: sameness declared again below an abstract base or trait
  • E07184: '#?' must go with the sameness

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: