What operators can be used with function-typed type parameters in generics?
← Generics · Ref: Q650
When a generic type parameter happens to be filled with a function type, only the '?' (isSet) operator is supported. Other operators like '+', '-', ':=:', ':^:', ':~:' are not applicable to function types.
ONLY QUESTION MARK
Function types support only '?' to check if they are set:
if callback? // function is assigned and ready to call
WHY LIMITED
Function types represent callable code, not data values. Arithmetic operators (+, -, *) make no sense on functions. Copy/merge/replace operators (:=:, :~:, :^:) would have unclear semantics for closures with captured state.
CORRECT USAGE
Check if a function parameter is set, then call it:
if handler? result <- handler(inputData)
DESIGN PRINCIPLE
Functions are called, not manipulated. EK9 treats functions as first-class values for passing and storing, but arithmetic and mutation operators are reserved for data types.
See Q647 for function constraint prohibition. See Q649 for generic function implementation. See Q58 for generic functions.
Example
defines module qa.genericsdeep.functioningeneric defines function <?- A simple function type that can be used as a type parameter. -?> formatter() as open -> item as String <- rtn as String: item defines class <?- Generic class that stores a value of type T. When T is a function type, only ? operator works. This example uses T with standard types, showing the ? operator that works for all types including functions. -?> Holder of type T stored as T? //A generic that may hold a FUNCTION cannot give its field an unset 'T()' (you cannot construct a //function - E06110), so the no-arg default is 'default private': you cannot externally create an //empty one, you must use the inferred constructor with a value. default private Holder() as pure Holder() as pure -> initialItem as T stored :=? initialItem isPresent() as pure <- rtn as Boolean: stored? default operator ? defines program FunctionInGenericDemo() stdout <- Stdout() // === STANDARD TYPE: all operators work === intHolder <- Holder(42) stdout.println(`Int holder present: ${intHolder.isPresent()}`) strHolder <- Holder("hello") stdout.println(`String holder present: ${strHolder.isPresent()}`) // === FUNCTION TYPE: only ? works === upperFormatter <- () is formatter as function rtn: item.upperCase() funcHolder <- Holder(upperFormatter) stdout.println(`Function holder present: ${funcHolder.isPresent()}`) // === LIMIT: a function-holding generic cannot be empty-constructed === // 'Holder() of Integer' is NOT available: the no-arg default is private because 'T()' is unavailable // for a generic that may hold a function. Construct with a value via the inferred constructor instead.
Common mistakes
E50060 — When a generic type parameter is filled with a function type, only the '?' (isSet) operator is supported. Operators like '+', '-', ':=:', ':^:', ':~:' are not applicable to function types. Functions are called, not manipulated with arithmetic or mutation operators. See ek9 -h E50060 for details.
Incorrect:
combine() as pure -> other as T <- rtn as T: stored + other
Correct:
isPresent() as pure <- rtn as Boolean: stored?
Other ways to ask this
- What is E06120 function used in generic operator restriction?
- Why can I only use the ? operator on function type parameters?
- What limitations exist for function types in generic contexts?
Coming from another language?
Java: function interfaces support only apply/invoke. C++: std::function supports only call operator. Rust: Fn traits define only call semantics. Go: functions only support calling. Kotlin: function types support only invoke. EK9: function type parameters in generics limited to '?' operator only.
Keywords: limitation, E06120, function, type-parameter, isSet, generic, operator, question, callable