changing the state of a program
Bugs of Mutated State
Bugs caused by changing the state of a program in ways that create unpredictability, where information and control flow become untraced.
Results diverge from expectations when state changes go untracked.
01the defects
The defects in detail
mutable bindings that drift out from under youvar / let / mut DeclarationsA binding you can reassign is a binding the next reader cannot trust.Read the defect two names for one value that changes under bothAliasing & Mutable DefaultsWhen two references share one mutable value, a write through either is a surprise to the other.Read the defect hand-rolled counters and tangled break / continuefor-Loop Control FlowManual loop control invites the index and the collection to disagree.Read the defect methods that rewrite the object they live onthis MutationWhen a method mutates this, every caller is coupled to call order.Read the defect reading the clock, the coin, and the diceTime, Money & EntropyA function that consults wall-clock time or money in floats answers differently every call.Read the defect hidden inputs, hidden effectsImpure FunctionsA function whose result depends on more than its arguments cannot be trusted or tested.Read the defect code that rewrites code, out of sightMacro & Mixin MisuseMetaprogramming expands or mixes behavior the reader never sees.Read the defect bump a number past the edge and it wraps++ / -- & Integer OverflowPre- versus post-increment hides off-by-one and double-counting; bump a fixed-width integer past its max and it silently wraps to the bottom.Read the defect read before it was ever writtenImproper InitializationThe first state transition — undefined to defined — is the purest mutated-state bug: use a value before it exists and every later read inherits garbage.Read the defect
02the smell
In practice
These nine defects share one root: state that changes where nobody is watching. It shows up downstream — wrong results, flaky tests, output that won't reproduce — long after the mutation that caused it. The tools that make it easy are the everyday ones: a reassignable binding, a hand-rolled loop counter, a method that quietly rewrites its object.
How it shows up
- Wrong or unexpected results
- Unpredictable function output or operation
- Edge cases abounding in code
- Test flakiness and complexity
Tools that hurt
let / var / mutfor loops and control flowclasses and this misuseuninitialized state / defaultsMath.random() & Date.now()macros & mixin misuse++ / -- & overflowbinary operators
03the dream
The pure-function fantasy
Through gradual practice and research, write entirely pure functions in typed languages on sandboxed VMs in a Faraday cage — only then can you never make a mistake when writing software.the unreachable ideal (said with a wink)
04antidotes
Philosophies & antidotes
This family maps to the CWE pillar: CWE-664 — Improper Control of a Resource Through its Lifetime