Tuesday, July 29, 2008

More considerations about immutable classes

Immutable classes and the Flyweight pattern.

Tim High (who happens to be the lead architect at the company I work on) correctly points out the relationship between immutable classes and the Flyweight [GoF] pattern. This pattern is another example of when immutable classes should be used. Because a Flyweight object can be potentially shared by many reference objects, flyweight classes should always be immutable.

Attribute sharing

We know that immutable classes help reduce the memory usage because they allow instances to be shared freely. But immutable classes can also share their attributes between instances of the same class, further reducing their memory footprint. String does exactly that:


String a = new String("Hello world");
String b = new String(a);


In the code above, both b and a point to the same array of characters. The constructor that takes another String takes care of not making an unnecessary copy of the array.

Note: Both lines above are bad Java idiom. You should do instead:


String a = "Hello world";
String b = a;


Consider using static factory methods

If you have a limited domain of possible values for your immutable class, you should consider creating static factory methods that return instances from a pool. One classic example is the java.lang.Integer class, that provides the valueOf(int i) method to be used instead of the constructor. Here is the implementation of this method:

public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) {
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}

This method returns a a reference from a pool if the value of the argument is between -128 and 127. You should not only use this method whenever possible, and the equivalents in the other Java wrapper classes, but you should also consider creating similar ones for your own immutable classes.

One final note on the value of immutable classes

One reason why people end up choosing not to make their classes immutable is because the benefits of immutability are less tangible then the benefits of mutability.

If you make your class mutable, you often can 'take a shortcut' in situations where immutability would have added some overhead. If String was mutable, you would never have to create a StringBuffer to do String concatenation in a loop. And the designers of the String class wouldn't have had to 'waste' time writing the StringBuffer class in the first place! But think of the thousands of bugs that would have shown up everywhere when some object inadvertently changed a String that was shared with another object!

So this is a small price to pay for benefits that are not so immediate, which are the elimination of nasty bugs caused by increased coupling, and the reduced memory usage by increased sharing.

Sunday, July 27, 2008

Immutable Classes

I recently had a discussion with my team regarding immutable classes. Some team members agreed that immutables simplify the development and add safety to the code, but some argued that its disadvantages outweight its advantages. Another question that popped up was when to use them and when not to use them.

Overview

Before I can look at each of the issues above with more detail, I will do a quick overview of immutables. A class is said to be immutable if the state of an object of that class can't be changed after the object is created. In Java, you achieve this by not providing any setters or, more generally, any public methods that can change the value of a field. You can reinforce the immutable condition by making all fields final. Usually you will also want to make the class itself final, so that a malicious user doesn't extend the class and adds mutability.

The fields of the an immutable class should be either immutable themselves, or not reachable from outside of the class. This is to avoid someone from modifying a private field of an immutable class. If you want to expose a non-immutable field of an immutable class through a getter, for instance, you should make a copy of the field and return the copy instead. The same thing is valid for when a mutable object is passed to the constructor of an immutable class. In this case, you need to make sure to make a copy of the object and store the copy instead.

Examples of immutable classes in Java are java.lang.String and the wrapper classes like java.lang.Double, java.lang.Integer and so on. One example of a class that is not immutable but should be is the java.util.Date class.

Advantages

The main advantage of an immutable class is that you don't need to copy objects for safety reasons. Lets say you are writing a method that receives a String as a parameter and sets it to a field of the class that implements the method. You don't need to make a safety copy of the String. Since the String class is immutable, there is no risk that someone else will change the object outside of your class. Similarly, you don't need to make a copy of the String when returning it via a getter.

But if you write a method that receives a Date parameter, or a getter that returns a Date field, you will probably want to make a safety copy of that Date, otherwise you can have nasty bugs when someone inadvertently changes the Date object that you returned.

Here is an example of a bug that can happen in this case (taken from here):

task1.setStartDate(new Date("1 Jan 98");
task2.setStartDate(task1.getTaskDate());
//then somewhere in the task class
void delay(int delayDays) {
_startDate.setDate(_startDate.getDate() + delayDays);
}

// then somewhere
task2.delay(5);
Then you find that task1's start date has changed.

Another advantage is that you get thread safety for free. Since no field can be modified, you can share objects between threads without having to synchronize the calls to the object.

Yet another advantage of immutable classes is that they automatically reduce coupling. Even if a String instance is shared among many other objects, there is no coupling because there is no shared state. One object can never affect the state of another object through this String.

Disadvantages

The main disadvantage of immutable classes is that it may be a pain in the neck to use them in iterations where they have to be constantly updated. In this case, for each iteration you have to create a new instance of the class with the updated values. This was cited in the discussion I had with my team as a reason not to use immutables.

But this problem can be easily solved by providing a companion mutable class. Back to the String example, Java provides the StringBuffer class that you should use when you have to make frequent updates to a String. But common sense dictates that the usage of the mutable class should be as localized as possible. You start with a String, then you create the StringBuffer to be updated in a loop, and at the end of the loop you convert it back to a String and get rid of the StringBuffer. You usually don't pass StringBuffers around among classes or set them as fields of other classes.

When to use them

One situation when you should always use immutable classes is when the class models a value object. Value objects are things like Strings, Dates, Numbers, Money, etc. You can have other Value Objects that are specific to your domain. Value objects should always be immutable. Martin Fowler says here: " If you are using a Value Object that is mutable, treat it like it is immutable. You may not realize why, but you will save a lot of time and money". Value Objects are a whole topic on their own, so I won't get into details here, but you can look at the links above for more information.

You don't need to go in an immutable class frenzy. Classes that model business entities shouldn't be immutable, since they usually have attributes that change over time, and there is a legitimate reason to share the same instance of a business entities between classes.

One way to identify value objects is by asking yourself if two instances of the same class with the same values are equivalent. If yes, your class is probably a value object. Two business entities may have the same values in its attributes but still represent different entities and have different database primary keys.

Conclusion

Immutable classes greatly improve the quality of your code by avoiding nasty bugs and reducing coupling. They are specially recommended for value objects, since they are passed around quite frequently. They shouldn't be used for business entities.