What are mutation operators and how do they differ from pure operators?
← Operators and Expressions · Ref: Q241
Mutation operators modify an object in place. They CANNOT be marked pure and MUST NOT return a value. This is the opposite of arithmetic operators like + which create NEW values and MUST be pure.
COMPOUND ASSIGNMENT
The +=, -=, *=, /= operators modify the object in place. They take 1 argument and return nothing.
score += 10 balance -= withdrawal count *= factor
These are equivalent to reassigning: score: score + 10, but more concise.
INCREMENT AND DECREMENT
The ++ and -- operators take 0 arguments and return nothing.
counter++ remaining--
COPY, MERGE, REPLACE
The :=: (copy), :~: (merge), and :^: (replace) operators are mutation operators. They take 1 argument and return nothing.
target :=: source config :~: partial record :^: replacement
Copy overwrites all fields. Merge copies only SET fields. Replace is a full content replacement.
PIPE OPERATOR
The | (pipe) operator is a mutation operator used in stream processing. It takes 1 argument and returns nothing.
PURE VS MUTATION: THE KEY DISTINCTION
Pure operator + creates a NEW value:
c <- a + b
The original 'a' is unchanged. A new value is created and assigned to 'c'.
Mutation operator += modifies IN PLACE:
a += b
The object 'a' is directly modified. No new value is created.
IMPLEMENTING MUTATION OPERATORS
Mutation operators CANNOT have 'as pure' and MUST NOT have a return declaration:
operator += -> other as MyType this.value: this.value + other.value
operator ++ this.value: this.value + 1
See Q98 for record copy, merge, replace. See Q240 for pure arithmetic operators. See Q238 for the complete operator set. See Q273 for how purity prevents mutation-based security attacks.
Example
defines module qa.operators.mutation defines class Counter count <- Integer() Counter() as pure -> initial as Integer this.count :=: initial // Pure: creates NEW value operator + as pure -> other as Counter <- rtn as Counter: Counter(count + other.count) // Mutation: modifies IN PLACE operator += -> other as Counter count += other.count operator ++ count++ operator -- count-- operator :=: -> source as Counter count :=: source.count operator $ as pure <- rtn as String: $count override operator ? as pure <- rtn as Boolean: count? defines program MutationDemo() stdout <- Stdout() // === PURE + CREATES NEW VALUE === a <- Counter(10) b <- Counter(5) c <- a + b stdout.println(`a after +: ${a}`) stdout.println(`c (new value): ${c}`) // === MUTATION += MODIFIES IN PLACE === a += b stdout.println(`a after +=: ${a}`) // === INCREMENT AND DECREMENT === counter <- Counter(0) counter++ counter++ counter++ stdout.println(`After 3 increments: ${counter}`) counter-- stdout.println(`After decrement: ${counter}`) // === COPY === original <- Counter(42) copied <- Counter(0) copied :=: original stdout.println(`Copied: ${copied}`)
Common mistakes
E07510 — Mutation operators (+=, -=, :=:, :~:, :^:, ++, --) modify the object in place and CANNOT be marked pure. Adding 'as pure' to a mutation operator triggers E07510. See ek9 -h E07510 for details.
Incorrect:
operator += as pure -> other as Counter count += other.count
Correct:
operator += -> other as Counter count += other.count
Other ways to ask this
- What is the difference between + and += in EK9?
- How do increment and decrement work in EK9?
- Which EK9 operators modify the object in place?
Coming from another language?
Java: += is syntactic sugar for x = x + op, ++ is increment, no copy/merge/replace operators. Python: __iadd__ for +=, no ++ operator, copy via copy.copy(). Rust: AddAssign trait for +=, no ++ operator, Clone trait for copy. Go: += is built-in, ++ is statement-only (not expression), no custom operators. Kotlin: plusAssign for +=, ++ via inc(), no merge/replace. JavaScript: += and ++ are built-in, no custom operator definitions. EK9: +=, -=, *=, /= (compound assignment), ++, -- (increment/decrement), :=: (copy), :~: (merge), :^: (replace), | (pipe), all CANNOT be pure, MUST NOT return value.
Keywords: pipe, place, immutable, replace, compound, expression, side-effect, mutate, merge, copy, assignment, mutation, modify, effect, operator, decrement, increment, side, pure