E07620: operator not defined

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

What went wrong

The type has no '<op>' operator - the one the message names (for example '$' on a record, '<=>' on a class, '+' on your own value type). EK9 never synthesises an operator silently: declare it. For '?', '$', '$$' or ':=:', 'default operator <op>' generates that one operator from the type's fields, or write 'operator <op>' by hand when the default semantics are not what you mean. Note '$' (to String) and '$$' (to JSON) are different operators - declare the one the message names.

The comparisons '==', '<>', '<', '<=', '>' and '>=' are different: they are ALWAYS generated from the type's SAMENESS and are never declared or requested one by one ('default operator <' is E07181). Give the type its sameness - 'default operator <=>' (ordered) or 'default operator ==' (equatable only), the bare 'default operator', or '<=>' / '==' written by hand - and the comparisons follow. '<', '<=', '>', '>=', '<?' and a 'sort' need '<=>'; an equatable-only type has '==' and '<>' only.

A PriorityQueue with no comparator orders its elements by '<=>' too, so 'PriorityQueue() of X', 'PriorityQueue(x)' and 'collect as PriorityQueue of X' need an X that can be ordered. For an X with no '<=>' build the queue with a comparator in the same expression: '(PriorityQueue() of X).withComparator(c)'. A queue built first and given its comparator in a later statement is the same error - the construction itself must carry it.

A second common shape is '~x in list' or '(not x) in list': '~' (and a parenthesised 'not') applies to x itself, and a String/Integer/record has no '~' (not) operator. Word 'not' binds below the comparisons, so 'not x in list' is the negated membership test, as are 'x not in list' and 'list not contains x'.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 1101 (Check if 'banana' is in a list of approved fruits.)
  • ek9 -q 100 (How do EK9 enumerations differ from Java enums?)
  • ek9 -q 137 (How do I manage resources with try-with-resources in EK9?)
  • ek9 -q 30 (How do I work with Boolean values?)
  • ek9 -q 37 (How do I work with strings in EK9?)
  • ek9 -q 129 (What happens when I access a Dict key that doesn't exist ...)

How to fix it

  1. For a comparison ('==', '<>', '<', '<=', '>', '>='): give the type its sameness - a defaulted '<=>' (ordered) or '==' (equatable only), the bare default form, or '<=>' / '==' by hand - and the comparisons follow; never request them one by one (E07181). For any other operator: declare the one the message names - generate it from the fields ('default' before it), or write it by hand. '$' is the String form, '$$' the JSON form; declare the one that is missing
  2. If the message names operator '~' on a non-Boolean: you negated x itself ('~x ...' or a parenthesised 'not x'), so the negation applies to x, not to the test after it. For membership, negate the whole test: 'x not in list' or 'list not contains x'.
  3. For a PriorityQueue of a type with no '<=>': build it with '(PriorityQueue() of X).withComparator(comparator)', or give X its '<=>'
  4. Check types on both sides match operator expectations

Common causes

  • Operator not implemented for custom type (a record used with '$', '==' or '<=>' and no 'default operator' declared)
  • '<' or a 'sort' on an equatable-only type (a defaulted '==' gives no '<=>'): default '<=>' in its place
  • Declaring '$$' (JSON) when the message named '$' (String), or the reverse
  • '~x in list' for a membership test - write 'not x in list' or 'x not in list'
  • A PriorityQueue of a type with no '<=>' (a List, a class with no '<=>') built with no comparator - or with the comparator added in a later statement
  • Type mismatch between operands
  • Missing 'default operator' declaration
  • Ordering a type whose bare 'default operator' could not give it '<=>', because a field (its own, or one on a super it follows) has none - with '<=>', '<', '<?', a 'sort' stage, 'in' a range, a 'for' range, or a generic that orders its T. Write '<=>' by hand, or sort with a comparator function

See also

  • E07620: operator not defined (this error)
  • E50060: named method not found

Examples

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

Fails with E07620: operator not defined

#!ek9
defines module error.e07620.bad

  defines record

    Score
      points as Integer: 0

      Score()
        -> initial as Integer
        points: initial

      default operator ==
      default operator ?

  defines function

    ranked()
      -> scores as List of Score
      <- rtn as List of Score: List()
      cat scores | sort > rtn

Fixed: Give the record an ordering: default <=> in place of ==, and == comes with it

#!ek9
defines module error.e07620.good.fix

  defines record

    Score
      points as Integer: 0

      Score()
        -> initial as Integer
        points: initial

      default operator <=>
      default operator ?

  defines function

    ranked()
      -> scores as List of Score
      <- rtn as List of Score: List()
      cat scores | sort > rtn

Fixed: Or leave the type as it is and sort with a comparator function

#!ek9
defines module error.e07620.good

  defines record

    Score
      points as Integer: 0

      Score()
        -> initial as Integer
        points: initial

      default operator ==
      default operator ?

  defines function

    byPoints() as pure
      ->
        first as Score
        second as Score
      <- rtn as Integer: first.points <=> second.points

    ranked()
      -> scores as List of Score
      <- rtn as List of Score: List()
      cat scores | sort by byPoints > rtn

Questions and answers

These Q&A entries show E07620 and its fix: