E07190: 'default' of operators requires super to have appropriate operator

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

What went wrong

You're using 'default operator' in a class that extends another class, but no class ABOVE it has the required operator. Default operators in derived classes call the NEAREST version above them first - the super's, or one further up the chain when the classes in between declare none (a field-less class in the middle needs nothing of its own).

When nothing above has the operator (only 'Any'), the message NAMES where it belongs: the nearest super class that has fields of its own - the root of the data decides whether its fields are exposed - or, when no super class has fields, the root of the hierarchy. Add 'default operator <op>' THERE. For the [EXAMPLE] below the message reads "Relating to 'Holder' requires operator '$()': nothing above 'Leaf' has it; add 'default operator $' to 'Holder' (the nearest super class with fields)".

SAMENESS ('==' and '<=>') is different. A generated '==' or '<=>' compares the type's own fields and leaves the inherited ones to the super's sameness - a '==' or '<=>' that takes the super itself, matched by its signature. So:

  • When the super chain HAS fields and nothing above compares them, it is this error. A '==(Integer)' or '<=>(Integer)' in the super does not count: it compares with an Integer, not with the super.
  • When the super chain has NO fields, there is nothing to compare: the generated one compares only the sub-type's own fields, with no call to the super, and is legal.

So the fix is to give the super class with fields its sameness - the sub-type then keeps its own 'default operator ==' or '<=>', which compares its own fields after the super's (a sub-type that adds fields must declare its own: E07238) - or to write the sub-type's operator by hand.

AN EQUATABLE-ONLY SUPER (one with '==' and no '<=>') cannot be built on by a GENERATED '<=>'. The message reads "'Base' is equatable only - a generated '<=>' has no '<=>(Base)' to order Base's fields first; write '<=>' by hand, or declare 'default operator =='". A sub-type of an equatable-only type may be ordered by a HAND-WRITTEN '<=>' only, which says itself how Base's fields take part; or it keeps '==' ('default operator ==', or the bare 'default operator', which follows the super). Below sameness written BY HAND on an abstract base or a trait the sub-type may declare no sameness at all: that is E07182, reported in place of this error.

A SUPER THAT CANNOT BE ORDERED has no '<=>' either. The bare 'default operator' gives a type '<=>' only when every field can be ordered; a field whose type has '==' only (or a List, a Dict) leaves it '==' and '#?'. A sub-type follows its super: below it, the bare 'default operator' gives '==' and '#?' only, and an explicit 'default operator <=>' is this error - the message says which super cannot be ordered and which field causes it. Declare 'default operator ==' on the sub-type (good_follows.ek9), give the field's type a '<=>', or write the sub-type's '<=>' by hand.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 1314 (Why does 'default operator' in a derived class fail wh...)

Note

Each 'default operator' shows only ONE error at a time. Fix the first, then you may see additional errors for other missing operators.

How to fix it

  1. Add 'default operator <op>' to the class the message names (the nearest super class with fields, or the hierarchy's root)
  2. For '==' or '<=>': give the super class with fields its sameness; the sub-type's own then compares its fields after the super's
  3. Below a super that cannot be ordered, or one that is equatable only, default '==' instead - or, below an equatable-only super, write '<=>' by hand.
  4. Or implement operators manually in derived class
  5. Each missing operator is reported separately

The [EXAMPLE] section below shows both cases (the message names 'Holder', the nearest super class with fields; and the root 'Plain' when none has fields), the fix of adding the operator above, and the alternative of writing the operator by hand (good_written.ek9). It also shows 'Detailed' asking for '<=>' below 'Labelled', which cannot be ordered, and the fix of following the super with '==' (good_follows.ek9).

Common causes

  • Base class has no operators defined
  • Inheritance chain missing operator implementations
  • Using default in derived class without checking super
  • A super '==' or '<=>' that takes another type ('==(Integer)'), which is not the super's sameness
  • 'default operator <=>' below a super whose bare 'default operator' cannot order one of its fields
  • 'default operator <=>' below an equatable-only super ('default operator ==' there, or a hand-written '==')

See also

  • E07190: default operator missing in super (this error)
  • E07180: default operator missing prerequisite in same class
  • E07182: hierarchy-wide sameness (written by hand on an abstract base or trait) is sealed

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E07190: 'default' of operators requires super to have appropriate operator

#!ek9
defines module error.e07190.bad

  defines class

    Root as open
      default operator ?

    Holder extends Root as open
      code as Integer: Integer()

      Holder() as pure
        -> initial as Integer
        code :=? Integer(initial)

      default operator ?

    Middle extends Holder as open
      Middle() as pure
        -> initial as Integer
        super(initial)

    Leaf extends Middle
      name as String: String()

      Leaf() as pure
        -> initial as Integer
        super(initial)
        name :=? String("leaf")

      default operator ?
      default operator $

    //No super class has fields: the message names the root, Plain.
    Plain as open
      default operator ?

    PlainLeaf extends Plain
      label as String: String()

      default operator ?
      default operator $

    //Equatable only, so Labelled's bare 'default operator' cannot give it a '<=>'.
    Tag
      text as String: String()

      Tag()
        -> text as String
        this.text: text

      default operator ==

      default operator ?

      default operator $

      default operator $$

      default operator #?

      default operator :=:

    Labelled as open
      tag as Tag: Tag("t")

      default operator

    Detailed extends Labelled
      detail as String: String()

      default operator <=>

      default operator ?

      default operator $

      default operator $$

      default operator :=:

Fixed: Give a super with fields the operator too

#!ek9
defines module error.e07190.good

  defines class

    Root as open
      code as Integer: Integer()

      default operator ?
      default operator $

    Leaf extends Root
      name as String: String()

      default operator ?

      //Root has its own '$', so the generated one can call it for Root's fields
      default operator $

Fixed: Below a super that cannot be ordered, follow it with '=='

#!ek9
defines module error.e07190.good.follows

  defines class

    //Equatable only, so Labelled's bare 'default operator' gives it '==' and '#?' but no '<=>'
    Tag
      text as String: String()

      Tag()
        -> text as String
        this.text: text

      default operator ==

      default operator ?

      default operator $

      default operator $$

      default operator #?

      default operator :=:

    Labelled as open
      tag as Tag: Tag("t")

      default operator

    //A sub-type follows its super: '==' (with '#?'), built on Labelled's '=='
    Detailed extends Labelled
      detail as String: String()

      default operator ==

      default operator ?

      default operator $

      default operator $$

      default operator #?

      default operator :=:

Fixed: Or write the operator by hand in the sub-type

#!ek9
defines module error.e07190.good.written

  defines class
    Root as open
      code as Integer: Integer()
      codeText() as pure
        <- rtn as String: $code
      default operator ?

    Leaf extends Root
      name as String: String()
      default operator ?
      //Nothing above has '$', so Leaf writes its own instead of generating one
      operator $ as pure
        <- rtn as String: `${name} (${codeText()})`

Questions and answers

These Q&A entries show E07190 and its fix: