How to make complex objects immutable

immutability

The example I'm about to give is for the PHP language, but I think this scenario applies to most languages.

Let's say I have an object called Response and I want it to be immutable. Every method should return a new instance rather than modifying the state of the current instance. Responses have headers, so I create a method called withHeader($name, $value) that makes a copy of my response object, sets the header, and returns the new instance. It's pretty simple to use:

$newResponse = $oldResponse->withHeader('Content-Type', 'application/json');

Then I decide the headers actually have quite a few properties and I'd rather separate this out into a separate object called a HeaderBag. Now I want my Response to hold a HeaderBag but I still want it to be immutable.

I can't make the the bag a public property, like $response->headers because even if the $headers object is immutable, the property can still be reassigned. So maybe I add something like $response->getHeaders() which returns my HeaderBag object, but now how do I manipulate it?

If I move my withHeader method into this sub-object, then I wind up with something like $response->getHeaders()->withHeader(...). The withHeader method would presumably return a new HeaderBag since it too is immutable, but then what? I guess I'd end up with something like this:

$newResponse = $oldResponse->withHeaders($oldResponse->getHeaders()->withHeader($name, $value));

Which seems a bit ridiculous; to add a single value we have to clone two objects and write this abomination of a line. Sure, we can write a helper method on the Response object to shorten it, but the whole idea was to move all the header-related methods into the HeaderBag class.

Questions:

  1. Is there a better way to do this?
  2. If there isn't, is it even worth the effort/cost to make objects immutable?
  3. If we could design a new language with immutability in mind, what would this look like?

Best Answer

An http response can naturally be thought of as immutable, but only from the moment that it has been fully constructed and issued. Before that moment, various implementations of "response" classes in various environments are generally used as builders (see Builder Pattern) which get passed around in order for various routines to add to them piecemeal all the information that constitutes the final response. So, during the lifetime of the response as a builder, it is by its very nature mutable.

Now, it is still possible to take a class which is mutable by nature and turn it into an immutable class, but what I would like to suggest to you is that although doing so might be a fabulous exercise on paper, (the entire series of Erik Lippert's articles on immutability was nothing short of fascinating,) it is not really something that you would want to be doing in practice with any non-trivial class, because you end up with abominations precisely like the one you discovered. Plus, it is clearly not worth the effort, and it is stupendously wasteful in terms of computing resources.

So, my suggestion would be that if you really like the idea of an immutable response, (I like it too,) then rename your current response to ResponseBuilder, let it be mutable, and when it is complete, create an immutable response out of it and discard the builder.

Related Topic