MUTABLE AND IMMUTABLE PROBLEM AND SOLUTION

One of the first things considered when designing a new information holding class is whetheritshould be mutable (changeable) or immutable (not changeable), or maybe a little bit of both. There are some major pitfalls either way, but careful design can get rid of most of the problems. I will here present my view on a few patterns for this, and when to use them. Beginner or intermediate developers are the target audience, and general knowledge of Java and Object Oriented design is a must. Even the advanced user might find the Immutem Pattern interesting.



Why are immutable objects so good then? The are many reasons for sure, here are the three main ones:
Protection. You can send an immutable object to any class without worrying about it being altered by that class, and you never have to make a defensive copy. Same when you get one for local storage in your class (for instance a cache), you don't have to worry about whether the provider will hold on to a reference and change it later, invalidating your cache without you knowing about it.
Performance. Given point 1 you don't have to make defensive copies all the time. This means that you save the garbage collector some work which increases performance and decreases memory overhead, and we all want that don't we?
Thread safe. After creation any number of threads can access them simultaneously, without any synchronization. This reinforces point 2 as well.
We need a sample class to build, so lets say we want to make a Date class. This class will be very simple though, it will only hold a single point in time as a long, representing milliseconds.
Simple but True Immutability


Making an immutable object is not hard at all! Just make the member fields final private, the methods and the class itself final, and you are basically done! That class would be somewhat limited though. You can't subclass it should you want a mutable version, and you must have a constructor that has all contained data as arguments (since you can not set new data on the class after creating it). For simple classes such as Integer this is good enough, there is no need to change the data since it so easy, and fast, to create a new object instead of changing the old one.
public final class ImmutableDate
{
// final is good for two reasons, it saves you from accidentally changing the value and
// there is a compile time error if you forget to initialize it. final is your fiend, use it.
private final long date;


public ImmutableDate (long date)
{
// Since a long is passed by value we don't have to clone it.
// non-immutable arguments must be cloned before they are stored.
// This is usually called defensive copying.
this.date = date;
}


public final long getDate()
{
return date; // We don't have to clone this either.
}
}
Removing final from the class opens up the possibility for Joe Junior to make a subclass that, while it can't change or intercept the date value, it can add other mutable parts to the class, and that wasn't our intention, we want it to be truly immutable.
False Immutability


If you do want a mutable version of the class above you are out of luck. You can of course make another one that has the same data andis mutable, but not one that are of the same type. It is tempting to change the class to something like this to make it possible for a mutable subclass:
public class ImmutableDate // falsely immutable!
{
protected long date;


public ImmutableDate (long date)
{
this.date = date;
}


public final long getDate()
{
return date;
}
}
Now, you can make a mutable subclass:
public class MutableDate
{
public MutableDate (long date)
{
super(date);
}


public void setDate(long date)
{
this.date = date;
}
}
No sweat; we're done now aren't we? Not quite...
One might think that by simply using the appropriate type one can have both a truly immutable and a mutable version. Here are a few of the problems with this design:
Since the class itself is no longer final, anyone can make a subclass that changes the date field in any way. The date field must be protected and can't be final since the subclass should be able to change it. Any subclass actually. Making the field package private will at least confine this to only be possible for the classes in the same package.
You can give away an object that you have created yourself, and thus know for a fact is a real ImmutableDate, however any object received into your classes will have to be defensively copied to an ImmutableDate for storage, even if it is of the typeImmutableDate. Remember that MutableDate is a subclass of ImmutableDate and thus can be down casted to one.
Inverted False Immutability


Someone might argue that it is better to do the other way around, and actually it is, in a way. It has it's own set of problems though. If you make the immutable version subclass the mutable version and override all setXXX() method to throw an exception, you are halfway there. You can even make some parts final again, which is good. Here are a few of the pitfalls:
If a new method is added to the mutable (super) class, one have to 'remember' to override that in the immutable sub class to throw an exception. I said remember; if you don't get goose bumps from that word you haven't done much coding, or have way better memory than me..
The API for the immutable object is wrong, it contains the setXXX() methods. The compiler won't help us since you can't make the overridden methods private. You will only know if you are trying to break the immutability at runtime, if that code path is executed. This anti-pattern is a good way to insert bugs..
You have no control over what's actually happening in the mutable (super) class. Maybe the implementor of that class thought it would be good to correct the date for day time savings when the current time passes the cut-off time? Who knows, I have seen stranger things written in code...
The false immutable pattern, inverted or not, is seldom a good choice other than for small confined object hierarchies that you have utter and complete control over. You should probably stay away.
Lockable Mutable Objects


I have never seen this as an actual pattern, but there are times when this approach can be a good choice. Basically you only make aMutableDate class, but you make it lockable with some kind of semi-secret key. All MutableDate's methods that changes the state of the object must first call assertNotLocked() which throws an exception if the object is currently locked. These methods should be in this class, or probably in a helper class to avoid code duplication (which is bad):
private final LinkedList keys = new LinkedList(); // We don't synchronize for simplicity


public final void addLock(Double key) // Not null for simplicity here.
{
keys.add(key);
}


public final void removeLock(Double key)
{
// We can check the whole list or just the last key. Checking the whole list for
// the key will make it possible to unlock in a different order than when locking.
if (keys.getLast().equals(key)) // No range check for simplicity
keys.removeLast();
else
throw new LockException("Unknown Key");
}


protected final void assertNotLocked()
{
if (keys.size() > 0)
throw new LockException("Object Locked");
}
As with most patterns there are some pitfalls and problems to this approach. Here are some:
The API looks wrong since a locked object still has setXXX() methods. Maybe that isn't so bad, but it still looks plain wrong. Implementing a Lockable interface maybe soothes some of the pain, but it's still there.
You still have to 'remember' to call assertNotLocked(). Not as severe here though, since it is in the same class at least and not in a subclass as the Inverted False Immutable anti-pattern above..
The lock status check takes some time, not much but still. For some small objects that is used a lot (E.g. a Point) this would not be a good idea. Also memory is wasted on the lock list. That list can be created and destroyed depending on if there are any keys in it though.
The key locking has to be synchronized if this approach should be thread safe. This adds complexity and hampers performance.
There is the problem with how to store and maintain the keys...
This pattern also have some good things:
Any 'Lockable' object can be locked. Not only a good thing, but it makes defensive copies unnecessary. What's bad is that you have to resort to the documentation to know whether the object will be locked or not in some specific context. There are no warnings or errors at compile time.
Only one class. For small minimalistic projects this can be important. Class count increases the project .jar since the .zip format is not very good at compressing many smaller files compared to one big. Many classes also increases the class loading time.
A More Flexible Solution


This is my favorite immutable/mutable combo pattern I think. I don't know if it have a name already since I have never seen it in any book. Lets call it the Immutem Pattern?. It basically involves creating an interface with all getXXX() methods declared. Both the mutable and immutable class implements this interface. The immutable class should be written as the a True Immutable, as explained earlier. The mutable version adds all the setXXX() methods and can be a lot more flexible by not making methods final. Basically the mutable class forms a volatile and flexible branch.
Here is the possible problem with this approach though; code duplication, but it has a good enough solution. Since the getXXX() methods has to be 'implemented' in both classes, we have a problem. We can't extend the immutable class since it is, and should be, final. The solution is to only use the immutable class as a proxy to a private immutable object. The benefits of this approach isn't directly apparent in the code below because the methods are so simple.
Here is the pattern in code:
public interface Date
{
public abstract long getDate();


public abstract ImmutableDate getImmutableDate();
}


public class MutableDate implements Date
{
protected long date;


public MutableDate(long date)
{
this.date = date;
}


public long getDate()
{
return date;
}


public void setDate(long date)
{
this.date = date;
}


public final ImmutableDate getImmutableDate()
{
// We have to make a new one. It is guaranteed to be the correct class
return new ImmutableDate(date);
}
}


public final class ImmutableDate implements Date
{
private final MutableDate date; // Not a long, we proxy to a MUTABLE date.


public ImmutableDate (long millis)
{
date = new MutableDate(millis);
}


public final ImmutableDate getImmutableDate()
{
return this; // We are already immutable and the correct class.
}


// All getXXX() methods just transfers execution to the contained,
// and never exposed, MutableDate.
public final long getDate()
{
return date.getDate();
}
}
This pattern has some interesting aspects:
The ImmutableDate is truly immutable, so when that type is used we know we can trust it to not change, ever. *
Whenever the interface type Date is used, that can be either the immutable class or some mutable subclass. If we are going to store it and wants an immutable version for that, we just call getImmutableDate() on it. This will do a type safe defensive copy if a mutable version is given to us and there is almost no overhead if the Date object was already an ImmutableDate, since it just returns itself without cloning (no need).
The getXXX() forwarding to the mutable hidden version only costs one method call to a final object from a final method, which should be very fast and best of all, there are no code duplication.
We have a lot of choices when it comes to types. We can force an immutable type, or maybe a mutable one as an “out” argument to a method. Or we can use the interface type when we really don't care, though still without having to create a defensive copy should we want to have a immutable version of it, and that was already what it was. Best of both worlds as it seem.
We don't have to specify everything in the constructor to make a truly immutable class, we can use the mutable version as a 'builder' object and when we are done building we call getImmutableDate() on it to obtain the immutable version. This way you can save yourself from those ten-argument constructors, or a zillion different ones.
There are however some pitfalls, though no major ones:
We have now three classes. Consumes a bit of resources.
There are a negligible performance degradation from forwarding the getXXX() methods to another object.
There are one more thing though, the ImmutableDate are not truly immutable. Can you find the loop hole? That's right, we don't have total control over the contained MutableDate class, it might do some funny stuff... This is not such a big problem compared to the winnings , IMHO of course. And we do have absolute control of the type of that mutable class.
There is another thing that we could enhance this pattern with. The mutable class is now concrete making it impossible to exchange that implementation. It does not need to be though, it would be quite beneficial to make MutableDate an interface and put the implementation in a DefaultMutableDate class or something similar.
Fig 1. The Immutem Pattern with the mutable part as an Interface.
We are now building quite a class hierarchy out if this and that might not be desirable. I guess depending on the importance of the information being encapsulated one should choose a solution somewhere between this last, most flexible, pattern and the Simple but True Immutability pattern.
I am currently using this pattern for a DateRange class that encapsulate two Calendar objects and a lot of operations on them. Using theImmutem Pattern has held defensive copying to a minimum (you want that with Calendar objects..), yet I still have the choice of using mutable versions as well as exchanging the implementation of the mutable parts.
Mutable Members in an Immutable Class
 Both input and output (getter/setter) methods of an immutable class must make a deep defensive copy of all communicated objects, or you don't have a truly immutable class. If you don't copy the arguments the sender/receiver of those objects might change it at a later time, if they choose to hold on to a reference to it that is.

No comments:

Post a Comment