E07621: the type argument's operator does not return the type the generic uses it as
What went wrong
A generic's body is checked once, against the operators every 'T' is assumed to have, and each of those has a fixed return type: '+', '-', '*', '/', 'abs', '~', '#<', '#>', '>>', '<<', 'and', 'or' and 'xor' return 'T' itself; 'mod', 'rem', 'length', '#?', '<=>' and '<~>' return an Integer; 'empty', 'contains', 'matches', '?' and the comparisons return a Boolean.
When the generic is given a type argument, the operator that serves each use must not only exist (E07620) but also return a type the body can hold where it used the result - that return type with 'T' replaced by the argument. The type argument named in the message has the operator, but it returns something else: a '+' returning Integer on 'Total', so 'sumOf() of Total' would hand an Integer back as a 'Total'. An INHERITED operator counts the same: a 'Leaf' that has its super's '+', returning 'Base', does not return a 'Leaf'.
No conversion is made here: the body was written for the operator's assumed return type, so there is nowhere to insert a promotion ('#^').
A constrained 'T' ('of type T constrain by Base') is not checked this way: its body already uses Base's own operators, with their real return types.
Worked examples
Compilable source showing this error, and the fix - see the [EXAMPLE] section below (bad.ek9 and good.ek9).
How to fix it
- Make the operator return what the generic uses it as: Total's '+' returns a Total (as good.ek9 in the [EXAMPLE] section does)
- For an inherited operator, override it in the sub-type with a covariant return (Leaf's own '+' returning a Leaf), or parameterise the generic with the super type itself ('sumOf() of Base' accepts Leaf values)
- If the operator really means something else (a '+' that yields a count, say), give it a method name instead and do not use the generic for it
- Or constrain the generic's 'T' to the type ('constrain by Total') when the body is written for that type's own operators
Common causes
- An operator written to return a plain value (Integer, Float) rather than the type itself
- A sub-type used as the type argument, where the operator is inherited from a super type and returns that super type
- A built-in type argument whose operator returns a different type: '-' on Date, DateTime or Time returns a Duration; '/' on Money, Dimension or Millisecond returns a Float; '#<' and '#>' on String return a Character, and on Float, Money, Date, DateTime, Time, Bits, Dimension and Millisecond return another type
See also
- E07621: operator return type does not fit the generic (this error)
- E07620: operator not defined - the operator is missing altogether
- E07440: covariance mismatch - the rule an overriding operator's return type follows
- E50030: types not compatible - a type argument that is not the constraining type or a sub-type of it
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E07621: the type argument's operator does not return the type the generic uses it as
#!ek9 defines module error.e07621.bad defines class Total amount as Integer? Total() as pure amount :=? Integer() Total() as pure -> initial as Integer amount :=? Integer(initial) amountOf() as pure <- rtn as Integer: Integer(amount) //Returns an Integer, but 'sumOf' uses '+' on T as returning T - here a Total default operator ? default operator $ operator + as pure -> other as Total <- rtn as Integer: amount + other.amountOf() defines function sumOf() of type T -> first as T second as T <- rtn as T: first + second defines program Totals() stdout <- Stdout() totals <- sumOf() of Total stdout.println($totals(Total(1), Total(2)))
Fixed: Make the operator return the type itself, as the generic uses it
#!ek9 defines module error.e07621.good defines class Total amount as Integer? Total() as pure amount :=? Integer() Total() as pure -> initial as Integer amount :=? Integer(initial) amountOf() as pure <- rtn as Integer: Integer(amount) //A Total plus a Total is a Total default operator ? default operator $ operator + as pure -> other as Total <- rtn as Total: Total(amount + other.amountOf()) defines function sumOf() of type T -> first as T second as T <- rtn as T: first + second defines program Totals() stdout <- Stdout() totals <- sumOf() of Total stdout.println($totals(Total(1), Total(2)))
Questions and answers
These Q&A entries show E07621 and its fix: