What does a generic require of its type argument when its body uses an operator on T (E07620, E07621)?
← Generics · Ref: Q2249
Every operator the generic's body applies to 'T' becomes a requirement on each type argument, checked where the generic is parameterised ('sumOf() of Total'), not inside the generic.
The body is checked once, against the operators every 'T' is assumed to have, and each has a fixed return type: '+', '-', '*', '/', 'abs', '~', '#<', '#>' return 'T' itself; 'mod', 'rem', 'length', '#?', '<=>' return an Integer; 'empty', 'contains', 'matches', '?' and the comparisons return a Boolean. So for each operator the body uses, the type argument must:
- HAVE it, taking the argument type where the body passes a 'T' - otherwise E07620;
- RETURN what the body uses it as, that return type with 'T' replaced by the argument (or a sub-type of it) - otherwise E07621.
A 'Total' whose '+' returns an Integer has the operator, but 'sumOf' would hand that Integer back as a Total: E07621. An INHERITED operator counts too: a 'Leaf' that has its super class Base's '+', returning Base, does not return a Leaf. Parameterise with the super type ('sumOf() of Base' still accepts Leaf values), or override the operator with a covariant return.
No promotion ('#^') is made, because the body was written for the assumed return type. A constrained 'T' ('of type T constrain by Total') is different: its body uses Total's own operators with their real return types, so nothing is assumed and nothing more is checked.
Example
#!ek9 defines module qa.genericsdeep.operator.requirements defines function //The body uses '+' on T as returning T sumOf() of type T -> first as T second as T <- rtn as T: first + second 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, as 'sumOf' needs operator + as pure -> other as Total <- rtn as Total: Total(amount + other.amountOf()) default operator ? operator $ as pure <- rtn as String: $amount Base as open amount as Integer? Base() as pure amount :=? Integer() Base() as pure -> initial as Integer amount :=? Integer(initial) amountOf() as pure <- rtn as Integer: Integer(amount) operator + as pure -> other as Base <- rtn as Base: Base(amount + other.amountOf()) default operator ? operator $ as pure <- rtn as String: $amount //Inherits Base's '+', which returns a Base: 'sumOf() of Leaf' would be E07621 Leaf is Base Leaf() as pure super() Leaf() as pure -> initial as Integer super(initial) defines program OperatorRequirements() stdout <- Stdout() totals <- sumOf() of Total stdout.println(`Total: ${totals(Total(3), Total(4))}`) integers <- sumOf() of Integer stdout.println(`Integer: ${integers(3, 4)}`) //Parameterise with the super type: it still accepts Leaf values bases <- sumOf() of Base stdout.println(`leaves as Base: ${bases(Leaf(3), Leaf(4))}`)
Common mistakes
E07621 — 'sumOf' uses '+' on T as returning T, so with 'sumOf() of Total' the '+' on Total must return a Total; an Integer would be handed back as a Total. Return the type itself, or constrain the generic's T by Total. See ek9 -h E07621.
Incorrect:
<- rtn as Integer: amount + other.amountOf()
Correct:
<- rtn as Total: Total(amount + other.amountOf())
Other ways to ask this
- Why is 'sumOf() of Total' an error when Total has a '+' operator?
- Why does E07621 say my operator does not return the type the generic uses it as?
- Can I give a generic a type whose '+' returns an Integer?
- Why can't I use a subclass as the type argument when its super class has the operator?
Coming from another language?
Java generics cannot use operators on a type parameter at all; an interface bound ('T extends Addable<T>') states the requirement in the declaration. C++ templates check each use at instantiation, with long error messages from deep inside the template. EK9 checks each operator the body uses against the type argument where the generic is parameterised, return type included, and names the generic, the operator and both types in one error.
Keywords: E07620, E07621, constrain by, generic, operator on T, parameterise, return type, type argument