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:
Handler of type T constrain by SomeFunction // ERROR E06080
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:
process()
-> mapper as Mapper
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() -> arg0 as String <- rtn as Boolean: arg0? <?- 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: bound, constrain, trait, prohibited, constraint, constant, type-parameter, E06080, function, generic