Following a brainwave, a scientist writes something important on a blackboard. Then in large, friendly letters he writes above it, “PLEASE DO NOT ERASE THIS!”
He leaves the room to grab a coffee.
Five minutes later he returns, and another scientist is cheerfully cleaning the blackboard, removing all trace of that world-changing idea.
“B-b-but - didn’t you see the note???” yelps the first.
“The one that said, ‘don’t rub this out?’” replies the second.
“Oh…I thought it meant don’t get rid of the blackboard. I didn’t realise the contents were important too.”
So it may be with immutability. Take Scala for instance. Put an object
scala.collection.immutable.List and the list is guaranteed
never to change. It will always be a one-element list with that object
in it. But the object itself? No special guarantees there - it’s
still mutable as it was before.
In this case, the list is the wall and the object is the blackboard - one is firmly nailed to the other. But just like the blackboard, the object can change its meaning at will.
does - the object’s keys will not change, and the pointers1
associated with those keys will not change, but the things they point
Object.freeze() only freezes top-level
properties. In which case it might be better named
Object.frosting(). Again, the blackboard is fixed, but what’s
written on it is a movable feast.
All this seems odd coming from languages that have immutability as a core concept, like Clojure & Haskell. In those languages, if I give you access to my immutable list, you can do anything you like with it and it won’t affect me. I don’t need to know what you did; I don’t need to trust you to behave yourself; I can rely on guarantees from the language itself. If you try to write on my blackboard, you’ll find yourself transported to another room, with an identical blackboard that you’re free to do whatever you like with. Mine remains untouched.
And so sadly it seems that, like “isomorphic”2, “immutable” now has two meanings depending on where you first heard about it. In the new meaning, you need to know some implementation details before you can say what part of the data is fixed, and what is subject to change. That doesn’t sound very immutable to me…
(I confess I struggle to see the value of immutable frosting. It seems like, “immutability made easy for the language implementor,” not, “made valuable for the programmer.”)
Still, for the record, here’s a definition of immutability that I think’s unambiguous and useful:
If you call a pure function with the same immutable argument, you always get the same result.3
Sounds obvious, but up until a few days ago I thought that was the only meaningful meaning ‘immutable’ could have…
Meaning, “you can convert a value from one type to another and back without losing information,” or, “the same HTML can be rendered on the backend or the frontend.” ↩
You really can cross the same river twice. ↩