Change: We humans have a love/hate relationship with it. We like to tinker, toy, tweak, and by doing so, change something. We like to see that change when it in return gives us a feeling of accomplishment and/or purpose. We like to rock the boat. On the other hand, we like things to remain the same, which makes it clearer and easier for us. We don’t want to have to react to change or think about it. Smooth sailing.
This human duality, I believe, lies at the core of the discussion about immutability and its pros and cons in OO programming. And for that reason, a discussion it will probably always be.
Immutability in object-oriented programming, a working definition
An immutable object is an object whose state cannot be modified after its creation. In practice however, it is not as black & white as one might first think (which we simplicity-loving creatures like to do). There is a spectrum. The mutability, or number of possible states, of an object with multiple properties is higher if all the properties can be changed than that of the same object if only one property would be changeable. In other cases, a certain object can be considered immutable, but only under specific conditions. And what if an object behaves, to all the world, immutably, yet changes its internal state (remember those trees sneakily falling in the forest when there’s no one around)? Having said that…
The advantages of using immutable objects in OO Programming
- They are simpler to understand and reason about.
- They offer higher security than mutable objects.
- They are inherently thread-safe, which is a very desirable trait since concurrent/parallel programming (multi-threading) is all-caps HARD.
The (potential) disadvantages of using immutable objects
- With large systems where immutability is pervasive, constant destructing and rebuilding of object structures can result in performance problems quickly.
- Many data structures are easier to implement using mutable objects.
An extra complicating factor is that most popular modern OO programming languages, like Java and C#, are mutability-minded, so to speak. Apart from a little tooling support there are as far as I know no adequate safeguards from using mutability. Because of this you need to do a lot of the immutability lifting in code yourself. This is especially important since these languages are leaning heavily on passing around objects using its reference, which results in complexity explosions as systems using mutable objects grow larger.
Wrapping things up personally
Immutability is not a panacea. It is not a means to itself. There are trade-offs involved. There are no definite good or bad, or ‘one size fits all’ usages. And how you implement immutability depends on your programming language of choice. It is my opinion that the real-world problem that a software project addresses ought to drive the choices made during development, and the (im)mutability directions that should be taken. All I can offer at this point are two (deceptively) simple personal guidelines I have loosely formulated for my own benefit. Lightweight OO programming best practices that help me in trying to keep complexity down and produce a more intuitive ‘code contract for handling change’ for my fellow developer.
- Separate data and methods as much as possible, honouring the single responsibility principle.
- Limit mutability of object properties where you can.
That’s it. Other than that, it is just a matter of committing and remaining vigilant. But, since this is the time of new year’s resolutions, that should not be a problem. ;-)