Why does EK9 reject mutation operators on function types?

← Code Quality · Ref: Q738

Function types are callable references, not data containers. Mutation operators like :=: (copy), :~: (merge), :^: (replace), += (add-assign), and -= (subtract-assign) are not applicable to function types.

WHAT WORKS ON FUNCTIONS

Only these operations are valid on function variables:
- := (assignment) changes which function is referenced
- ? (isSet) checks if a function reference has been assigned

WHY MUTATION IS BANNED

Functions represent behaviour, not state. Copying, merging, or replacing functions has no meaningful semantics. Assignment (:=) changes the reference to point at a different function. That is fundamentally different from :=: which copies the internal state of an object.

COMMON MISTAKE

Developers coming from languages where lambdas are objects (Java, Python) try to use copy semantics on function references. In EK9, simply use := to reassign a function variable to a different function.

See Q49 for function basics. See Q52 for dynamic functions. See Q596 for function vs method distinction.

Example

defines module qa.codequality.functionmutation

  defines function

    Formatter as abstract
      -> text as String
      <- result as String?

    upperFormatter() is Formatter
      -> text as String
      <- result as String: text.upperCase()

    bracketFormatter() is Formatter
      -> text as String
      <- result as String: `[${text}]`

    applyFormatter()
      ->
        formatter as Formatter
        text as String
      <- result as String: formatter(text)

  defines program

    FunctionMutationDemo()
      stdout <- Stdout()

      //Function assignment with :=
      handler as Formatter: upperFormatter
      stdout.println(applyFormatter(handler, "hello"))

      //Reassignment with := is valid
      handler := bracketFormatter
      stdout.println(applyFormatter(handler, "world"))

      //isSet check with ? is valid
      stdout.println(`Handler set: ${handler?}`)

Common mistakes

E08240 — Function types do not support the copy operator :=:. Functions are references, not data containers. Use := (assignment) to change which function is referenced. See ek9 -h E08240 for details.

Incorrect:

handler :=: bracketFormatter

Correct:

handler := bracketFormatter

E08240 — Function types do not support the merge operator :~:. Use := (assignment) to reassign the function reference. See ek9 -h E08240 for details.

Incorrect:

handler as Formatter: upperFormatter
      handler :~: bracketFormatter

Correct:

handler as Formatter: upperFormatter

E08240 — Function types do not support the replace operator :^:. Use := (assignment) to change the function reference. See ek9 -h E08240 for details.

Incorrect:

handler :^: bracketFormatter
      stdout.println(applyFormatter(handler, "hello"))

Correct:

stdout.println(applyFormatter(handler, "hello"))
Other ways to ask this
  • What is E08240 mutation on function type?
  • Why can I not use copy operator on a function variable?
  • What operators work on function types in EK9?

Coming from another language?

Java: lambdas are objects with copy semantics via clone. Python: functions are objects that can be copied. JavaScript: functions are objects with spread/assign. Rust: closures implement traits, can be cloned if contents are Clone. EK9: function types are pure references, only := and ? are valid.

Keywords: E08240, replace, operator, callable, function, copy, quality, type, reference, mutation, merge