What happens when I use mutating operators in EK9?
← Operators and Expressions · Ref: Q905
Mutating operators in EK9 return 'this' — the SAME object, not a copy. This creates aliasing, similar to C++ references or Java mutable objects.
MUTATING OPERATORS
These operators modify the object IN PLACE and return the same object:
+= -= *= /= — compound arithmetic ++ -- — increment/decrement :=: — copy (overwrites all fields) :^: — replace :~: — merge
ALIASING DANGER
x <- 10 y <- x++ ERROR — ++ is statement-only in EK9
EK9 prevents this by making ++ and -- STATEMENT-ONLY operators. You CANNOT use them in expressions.
CORRECT USAGE
counter <- 0 counter++ OK — statement counter += 5 OK — statement
// To get a copy, use a separate declaration original <- 100 copied <- original creates independent copy copied++ only copied changes
NON-MUTATING OPERATORS
These create NEW objects and do NOT alias:
+ - * / — arithmetic (return new value) == <> < > <= >= — comparison (return Boolean) <=> — three-way compare (return Integer) $ — string conversion (return String) #? — hashcode (return Integer) #^ — promote (return wider type) ? — isSet (return Boolean)
RULE: If the operator changes the object, it is mutating and statement-only. If it produces a new value, it is non-mutating and can be used in expressions.
See Q96 for all operators. See Q238 for operator enforcement.
Example
defines module qa.operators.mutating defines function <?- Shows correct use of mutating operators as statements. ++ -- += -= are STATEMENT-ONLY, not expressions. -?> accumulateTotal() -> numbers as List of Integer <- runningTotal as Integer: 0 for n in numbers runningTotal += n <?- Shows non-mutating operators that create new values. + - * / return NEW objects, safe in expressions. -?> calculateAverage() as pure -> total as Integer divisor as Integer <- rtn as Float: 0.0 if divisor > 0 rtn := #^ total / #^ divisor defines program MutatingOperatorsDemo() stdout <- Stdout() // Mutating operators are STATEMENT-ONLY counter <- 0 counter++ counter++ counter++ stdout.println(`Counter after 3 increments: ${counter}`) counter += 10 stdout.println(`Counter after += 10: ${counter}`) counter-- stdout.println(`Counter after --: ${counter}`) // Non-mutating operators create NEW values (safe in expressions) productA <- 5 * 3 productB <- 7 + 2 stdout.println(`5 * 3 = ${productA}, 7 + 2 = ${productB}`) // Copying creates independent values original <- 100 copied <- original copied += 50 stdout.println(`Original: ${original}, Copied: ${copied}`) // Accumulation with += numbers <- [10, 20, 30, 40] total <- accumulateTotal(numbers) avg <- calculateAverage(total, length numbers) stdout.println(`Total: ${total}, Average: ${avg}`)
Common mistakes
E07950 — The ++ operator is statement-only and cannot appear inside an expression; increment first, then use the value. See ek9 -h E07950 for details.
Incorrect:
copied <- original++
Correct:
copied <- original
Other ways to ask this
- Do mutating operators create aliases in EK9?
- What does += return in EK9?
- Why does y <- x++ make x and y the same object?
- How do mutating operators work in EK9?
Coming from another language?
C++: mutating operators return references (aliasing risk). Java: += modifies in place, primitives are copied but objects are aliased. Rust: no implicit aliasing — ownership system prevents it. Go: no operator overloading. Python: += modifies in place for mutable types (lists), creates new for immutable (int). EK9: mutating operators are STATEMENT-ONLY — prevents aliasing bugs at compile time.
Keywords: compound, increment, copy, aliasing, mutating, expression, operator, statement, decrement