Why does EK9 reject reassignment in pure functions and parameter reassignment?

← Code Quality · Ref: Q737

EK9 enforces two reassignment restrictions to prevent hidden state changes.

PURE CONTEXT REASSIGNMENT (E08100)

In a pure function, ':=' on a local (non-returning) variable is rejected. Pure functions should compute results, not accumulate state. Two forms stay allowed: ':=?' (assign-if-unset, only sets if unset) and assignment to the return variable (rtn := start, or label: "excellent" as classifyScore does below). Mutating operators such as += are a separate ban in a pure scope (E08120), so they are not a way round E08100.

PARAMETER REASSIGNMENT (E08110)

You cannot REASSIGN a parameter (rawName := ...). The parameter names the caller's input, and pointing it at something else obscures the data flow. Instead, copy the parameter to a local variable and change the copy, as formatName does below.
Reassignment is not the same as mutation: in a non-pure function a parameter CAN be changed in place with a mutating operator (counterValue += 1, items += "x"), and the caller SEES that change, because the caller and the function share the same object.

WHY ENFORCED

Reassignment creates hidden state changes that are hard to reason about. Pure functions should be deterministic and side-effect free. Banning parameter reassignment keeps a parameter name meaning the caller's object for the whole body.

See Q678 for purity contracts. See Q635 for pure mutation restrictions.

Example

defines module qa.codequality.pureparamreassign

  defines function

    classifyScore() as pure
      -> score as Integer
      <- label as String: "average"

      highThreshold <- 90
      lowThreshold <- 40

      if score >= highThreshold
        label: "excellent"
      else if score < lowThreshold
        label: "poor"

    doubleValue() as pure
      -> input as Integer
      <- result as Integer: input * 2

    formatName()
      -> rawName as String
      <- formatted as String: rawName

      localName <- rawName
      localName := "Mr. " + localName
      formatted: localName

  defines program

    PureParamReassignDemo()
      stdout <- Stdout()

      stdout.println(classifyScore(95))
      stdout.println(classifyScore(30))
      stdout.println(classifyScore(60))

      stdout.println(`Doubled: ${doubleValue(21)}`)
      stdout.println(formatName("Smith"))

Common mistakes

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

stdout.println(classifyScore(95).toUpperCase())

Correct:

stdout.println(classifyScore(95))

E50060 — String has no toUpperCase() method in EK9. Use upperCase() instead. See ek9 -h E50060 for details.

Incorrect:

stdout.println(formatName("Smith").toUpperCase())

Correct:

stdout.println(formatName("Smith"))

E08110 — Parameters cannot be reassigned with :=. Copy the parameter to a local variable first, then change the copy. See ek9 -h E08110 for details.

Incorrect:

rawName := "Mr. " + rawName

Correct:

localName <- rawName
      localName := "Mr. " + localName

E50060 — String has no toString() method. classifyScore() already returns a String. See ek9 -h E50060 for details.

Incorrect:

stdout.println(classifyScore(95).toString())

Correct:

stdout.println(classifyScore(95))
Other ways to ask this
  • What is E08100 reassignment in pure context?
  • What is E08110 parameter reassignment in EK9?
  • How do I modify values in a pure function?

Coming from another language?

Java: parameters can be reassigned (but final prevents it). Kotlin: function parameters are val (immutable) by default. Rust: parameters are immutable by default, require mut. Python: parameters can be reassigned freely. Go: parameters can be reassigned freely. EK9: a parameter cannot be reassigned (E08110) but can be mutated in place outside pure scopes, visibly to the caller; a pure scope rejects ':=' on locals (E08100) but allows ':=?' and assigning the return variable, and rejects mutating operators (E08120).

Keywords: context, reassignment, quality, E08110, E08100, pure, parameter, restriction