A major point not yet mentioned is that having the state of an object be mutable makes it possible to have the identity of the object which encapsulates that state be immutable.
Many programs are designed to model real-world things which are inherently mutable. Suppose that at 12:51am, some variable AllTrucks
holds a reference to object #451, which is the root of a data structure which indicates what cargo is contained in all the trucks of a fleet at that moment (12:51am), and some variable BobsTruck
can be used to get a reference to object #24601 points to an object which indicates what cargo is contained in Bob's truck at that moment (12:51am). At 12:52am, some trucks (including Bob's) are loaded and unloaded, and data structures are updated so that AllTrucks
will now hold a reference to a data structure which indicates the cargo is in all the trucks as of 12:52am.
What should happen to BobsTruck
?
If the 'cargo' property of each truck object is immutable, then object #24601 will forevermore represent the state that Bob's truck had at 12:51am. If BobsTruck
holds a direct reference to object #24601, then unless the code which updates AllTrucks
also happens to update BobsTruck
, it will cease to represent the current state of Bob's truck. Note further that unless BobsTruck
is stored in some form of mutable object, the only way that the code which updates AllTrucks
could update it would be if the code was explicitly programmed to do so.
If one wants to be able to use BobsTruck
to observe the state Bob's truck while still keeping all objects immutable, one could have BobsTruck
be an immutable function which, given the value that AllTrucks
has or had at any particular time, will yield the state of Bob's truck at that time. One could even have it hold a pair of immutable functions--one of which would be as above, and the other of which would accept a reference to a fleet state and a new truck state, and return a reference to a new fleet state which matched the old, except that Bob's truck would have the new state.
Unfortunately, having to use such a function every time one wants to access the state of Bob's truck could get rather annoying and cumbersome. An alternative approach would be to say that object #24601 will always and forevermore (as long as anyone holds a reference to it) represent the current state of Bob's truck. Code which will want to repeatedly access the current state of Bob's truck wouldn't have to run some time-consuming function every time--it could simply do a lookup function once to find out that object #24601 is Bob's truck, and then simply access that object any time it wants to see the present state of Bob's truck.
Note that the functional approach is not without advantages in a single-threaded environment, or in a multi-threaded environment where threads will mostly just be observing data rather than changing it. Any observer thread which copies the object reference contained in AllTrucks
and then examines the truck states represented thereby will see the state of all the trucks as of the moment that it grabbed the reference. Any time an observer thread wants to see newer data, it can just re-grab the reference. On the other hand, having the entire state of the fleet represented by a single immutable object would preclude the possibility of two threads updating different trucks simultaneously, since each thread if left to its own devices would produce a new "fleet state" object which included the new state of its truck and the old states of every other. Correctness may be assured if each each thread uses CompareExchange
to update AllTrucks
only if it hasn't changed, and responds to a failed CompareExchange
by regenerating its state object and retrying the operation, but if more than one thread attempts a simultaneous write operation, performance will generally be worse than if all writing were done on a single thread; the more threads attempt such simultaneous operations, the worse the performance will get.
If individual truck objects are mutable but have immutable identities, the multi-threaded scenario becomes cleaner. Only one thread may be allowed to operate at a time on any given truck, but threads operating on different trucks could do so without interference. While there are ways one could emulate such behavior even when using immutable objects (e.g. one could define the "AllTrucks" objects so that setting state of truck belonging to XXX to SSS would simply require generating an object that said "As of [Time], the state of the truck belonging to [XXX] is now [SSS]; the state of everything else is [Old value of AllTrucks]". Generating such an object would be fast enough that even in the presence of contention, a CompareExchange
loop wouldn't take long. On the other hand, using such a data structure would substantially increase the amount of time required to find a particular person's truck. Using mutable objects with immutable identities avoids that problem.