Advertisement

Mutability sounds like abstract language-design trivia until it bites you: you change one variable and something else, seemingly unrelated, changes too. A whole family of baffling bugs traces back to not understanding whether a piece of data can be modified in place, and who else is holding a reference to it.

Getting this straight prevents a surprising amount of pain.

The core idea

Mutable data can be changed after it is created; immutable data cannot — any "change" produces a new value instead. When you pass mutable data around, multiple parts of your program may hold references to the very same object, so a modification in one place is visible everywhere. Immutable data, by contrast, cannot surprise you this way, because it never changes underneath anyone.

This is why languages and libraries increasingly favour immutability for shared state: it removes an entire category of "spooky action at a distance".

Advertisement

How it bites

The classic bug: you copy a list or object by assigning it to a new variable, assume you now have an independent copy, and then modifying the "copy" also mutates the original — because both names point at the same mutable thing. Shared mutable state across functions, threads or components produces some of the hardest bugs to reproduce, since the culprit is often far from the symptom.

The confusion is almost always "I changed A, why did B change?" — and the answer is that A and B were the same object all along.

Working with it safely

A few habits help: prefer immutable values for anything shared, be deliberate about when you truly want a copy versus a reference, and know your language’s rules for which types are mutable. When you need to modify shared data, make the sharing and the mutation explicit rather than accidental.

You do not have to make everything immutable. You do have to know which is which — because the bugs come from assuming, not from choosing.