“No man can cross the same river twice, because neither the man nor the river are the same.”
Heraclitus
The following post is extracted & paraphrased from Rich Hickey's excellent Are We There Yet? - specifically the section of the talk that focuses on the model for discussing and thinking about the titular concepts. These concepts are in turn taken from the philosophical writings of Alfred North Whitehead (a co-author of Principia Mathematica).
I often find myself wanting to explain this core concept to people who are new to Clojure, and particularly people who I am trying to make into people who are new to Clojure. While I think I have a good handle on this concept in my head - I sometimes struggle to explain it succinctly, hopefully this post achieves that goal.
Definitions
These definitions are not really globally applicable, but they represent the precise meaning I try to capture when discussing values changing over time in the context of software development and programming.
Value
A value is some measurable quantity, magnitude or amount for which its equivalence to some other value can be determined. A value can also be some immutable composite of other values. The number 42 is a value, the string "Hello World" is a value, the list (1, 2, 3) is also a value.
Identity
An identity is some composite psychological concept we apply to a succession of values over time where they are in some way causally related. You are an identity, I am an identity, a river is an identity (see below).
Name
A name is simply a label that we apply to an identity or a value to make it easier to refer to. The same identity can have many names. "Glen", "Glen Mailer", "Mr Mailer", "Glenjamin" and "@glenathan" are all names which could legitimately be considered to refer to the identity that is myself in the appropriate context. Likewise the "Answer to the Ultimate Question of Life, The Universe, and Everything" is a name for the value 42.
State
A state is simply the value of an identity at a particular time. A snapshot, if you will. Under this definition state does not change, and thus there is no such thing as "mutable state".
Time
Purely relative, it has no dimensions - it can only tell us whether something happened before or after some other thing (or at the same time).
The River
Let us consider the title quote in the context of these definitions. To help us examine the proverbial river under this light, we shall give ourselves the same powers as when running a computer program but in the real world - which requires us to sidestep some fairly fundamental physics - hopefully this will not cause any lasting damage.
The third-longest river in Asia runs through China. Depending on context it is known as the "Yellow River", "Huang He", "རྨ་ཆུ།", "the cradle of Chinese civilization" and "China's Sorrow". All of these are names for the same river, which itself is an identity.
If we were to freeze an instant in time into a snapshot of our proverbial river crossing, this state would contain a value composed of a large number of atomic (in the irreducible sense) smaller values. For simplicity, lets assume that water molecules are immutable. In this case then the state of the river we are crossing can be said to be the current arrangement of all these immutable water molecule values.
At some point in the future when returning for our second crossing, we take another snapshot of the river as our new state. The river's value is again the arrangement of all the immutable water molecules - but this time they are all different molecules with different values.
The state of the identity which is the river named "Huang He" at this later point in time is measurably different from the value we took during the first crossing.
In Clojure
Since immutability is at it's core, we'll start here for some code examples.
The following code should work correctly when pasted into a running Clojure REPL.
In JavaScript
JavaScript doesn't have the same set of immutable primitives, but we can achieve a similar effect with a little sleight of hand.
The following code should work correctly when pasted into the browser console or a Node.js REPL line-by-line.
Summary
The ancient Greeks knew about the perils of mutable state a long time ago - we're only now rediscovering this for ourselves.
In a language like Clojure, that was designed from the ground up with this in mind, it's easy to take back control and tease apart the separate concepts I've described. Even in a language like JavaScript, designed in a week at a time when mutability was commonplace, we can achieve a similar effect with a measure of self-control. There are also libraries like mori and immutable-js which provide much fuller implementations of the data-types required to avoid mutability.
If you remain unconvinced, I recommend watching Are We There Yet?. If you're still not sure after that, you're either a far better programmer than me, or you're yet to experience the pain of trying to reason about a large codebase riddled with unchecked mutability.
Addendum
As well as the above definitions, Are We There Yet? contains this gem, which is Rich visualising the idea of obvious complexity while saying "Grrrrr".