This is an AMP version of the article, its original content can be found here.
Gradients of Immutability
Good objects are immutable, but not necessarily constants. I tried to explain it here, here, and here, but now it's time to make another attempt. Actually, the more I think about it, the more I realize that immutability is not black or white—there are a few more gradients; let's take a look.
As we agreed here, an object is a representative of someone else (some entity or entities, other object(s), data, memory, files, etc.). Let's examine a number of objects that look exactly the same to us but represent different things, then analyze how immutable they are and why.
This is constant; it doesn't allow any modifications to the encapsulated entity and always returns the same text (I've skipped constructors for the sake of brevity):
This is what we usually have in mind when talking about immutable
objects. Such a class is very close to a
which means that no matter how many times we instantiate it with
the same initial values, the result of
title() will be the same.
Not a Constant
Check out this one:
The object is still immutable, but it is not a pure
function anymore because of the method
title()—it returns different values if we call it
multiple times with at least a one-minute interval. The object
is immutable; it's just not a constant anymore.
How about this one:
This immutable object keeps the book title in a file. It's not a constant,
because its method
title() may return different values on every
second call. Moreover, the represented entity (the file) is not a constant.
We can't say whether it's mutable or immutable, as we don't know how
is implemented. But we know for sure that it's not a constant, because it
accepts change requests.
An immutable object may not only represent but even
encapsulate a mutable one. Just like in the
previous example, a mutable file was encapsulated. Even though it
was represented by the immutable class
Path, the real file on disk
was mutable. We can do the same, but in memory:
The object is still immutable. Is it thread-safe? No. Is it a constant? No. Is it immutable? Yes. Confused? You bet.
My point is that immutability is not binary; there are many forms of it. The most simple one is, of course, a constant. Constants are almost the same as pure functions in functional programming. But object-oriented programming allows us to take a few steps forward and give immutable objects more permissions and flexibility. In OOP, we may have many more forms of immutability.
What is common among all these examples is that our objects are
loyal to the entities they encapsulate. There are no
that could change them. All encapsulated objects are
This is the only quality that differentiates mutable objects from immutable ones. The latter are always loyal to the entities they encapsulate and represent. For all the rest ... it depends.