Why cannot I use a function type as a generic constraint?
← Generics · Ref: Q647
EK9 does not allow function types as constraints in 'constrain by'. Only class types and traits can be used as constraints. Function types have a different dispatch model and cannot serve as type bounds.
PROHIBITED PATTERN
You cannot write:
defines function CheckFunction() -> text as String <- rtn as Boolean: text? describeItem() of type T constrain by CheckFunction as open // ERROR E06080 -> item as T <- rtn as String: $item
Function types cannot be used with 'constrain by'.
WHY PROHIBITED
Function types in EK9 define signatures (input types and return type). They are not class hierarchies with methods. Constraining T to a function would mean T must be callable, but EK9's generic system works with method access, not call-ability.
CORRECT ALTERNATIVES
Use a trait or abstract class as the constraint:
Handler of type T constrain by Processable
Define a trait with the methods you need, then constrain by that trait.
FUNCTION PARAMETERS
If you need to pass functions to generics, use function-typed parameters:
defines function Mapper() as abstract -> inputText as String <- rtn as String? process() -> mapper as Mapper <- rtn as String: mapper("input")
Where Mapper is a defined function type, passed as a parameter rather than a constraint.
See Q195 for constrain by with classes. See Q646 for inference limits. See Q649 for generic function implementation.
Example
defines module qa.genericsdeep.nofunctionconstraint defines trait <?- Correct approach: define a trait with the methods you need. Then constrain by the trait, not by a function type. -?> Describable description() as pure abstract <- rtn as String? defines class Planet with trait of Describable planetName as String? default private Planet() as pure Planet() as pure -> n as String planetName :=? String(n) override description() as pure <- rtn as String: String(planetName) override operator ? as pure <- rtn as Boolean: planetName? Star with trait of Describable starName as String? default private Star() as pure Star() as pure -> n as String starName :=? String(n) override description() as pure <- rtn as String: String(starName) override operator ? as pure <- rtn as Boolean: starName? defines function <?- A function type - cannot be used as a constraint. -?> CheckFunction() -> text as String <- rtn as Boolean: text? <?- Correct: constrain by a trait, not a function. The trait provides the methods needed inside the generic. -?> describeItem() of type T constrain by Describable as open -> item as T <- rtn as String: item.description() defines program NoFunctionConstraintDemo() stdout <- Stdout() planet <- Planet("Mars") planetDesc <- describeItem(planet) stdout.println(`Planet: ${planetDesc}`) star <- Star("Polaris") starDesc <- describeItem(star) stdout.println(`Star: ${starDesc}`)
Common mistakes
E50010 — The constraining type must be a resolvable class or trait. Using a name that does not exist triggers a type-not-resolved error. See ek9 -h E50010 for details.
Incorrect:
constrain by NoSuchTrait as open
Correct:
constrain by Describable as open
E06080 — Generic types cannot be constrained by function types. Use a trait or class as the constraint. See ek9 -h E06080 for details.
Incorrect:
describeItem() of type T constrain by CheckFunction as open
Correct:
describeItem() of type T constrain by Describable as open
Other ways to ask this
- What is E06080 constrained functions not supported?
- Can I constrain a generic type parameter to a function type?
- Why does EK9 prohibit function types in constrain by?
Coming from another language?
Java: can use functional interfaces as bounds '<T extends Function<S,R>>'. C++: concepts can constrain to callable. Rust: trait bounds with Fn/FnMut/FnOnce. Go: interfaces can include method signatures (callable). Kotlin: can bound by function types. EK9: function types excluded from 'constrain by', use traits instead.
Keywords: trait, constrain, bound, generic, function, E06080, type-parameter, constant, constraint, prohibited