E07620: operator not defined
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
- 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
- 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'.
- For a PriorityQueue of a type with no '<=>': build it with '(PriorityQueue() of X).withComparator(comparator)', or give X its '<=>'
- 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
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:
- Q30: How do I work with Boolean values?
- Q37: How do I work with strings in EK9?
- Q91: What advanced features do Integer and Float support?
- Q100: How do EK9 enumerations differ from Java enums?
- Q121: How does PriorityQueue work in EK9?
- Q129: What happens when I access a Dict key that doesn't exist in EK9?
- Q137: How do I manage resources with try-with-resources in EK9?
- Q244: How do boolean and bitwise operators work in EK9?
- Q279: Why does AI confuse EK9 operators with other languages?
- Q689: What are the correct patterns for boolean conditions and comparisons?
- Q897: What do the $ and #? operators mean in EK9?
- Q914: Does # mean comment in EK9 like Python?
- Q1159: Check if a country code is in a list of approved countries.
- Q1192: How do I increment a character and compare two characters in EK9?
- Q1386: How do I hash data in EK9, and what is the difference between Digest and HMAC?
- Q1387: How do I compute an HMAC in EK9, and how do I verify one safely?
- Q1398: How are defaulted comparison operators derived - does a defaulted == agree with my <=>?
- Q2160: What is EK9's operator precedence - does 'and' bind tighter than 'or', and where does 'not' sit?
- Q2281: Why does my class get only '==' and no '<' when one of its fields is an open class (E07620, E07188)?