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.
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 pure function, 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
Files.write() 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 setters 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.