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