Monday, April 20, 2009

Favoring immutability

A few years ago, when I read Effective Java for the first time, Item 13 really stuck in my mind: make your objects immutable wherever possible. You can share them freely. You don't have to worry about checking to see if that Person object you created still has a name. You made sure of that when you created it. And while I don't do a lot of concurrency programming, I've seen time and time again how much you get "for free" when you use immutable objects in multi-threaded environments. So that's another benefit.

OK, so I read the book, and moved on. Then I start working on a new project. We happened to pick GWT as part of the tool stack. During the early stages, a light bulb goes off in my head: hey, I'm writing a bunch of new beans in Java - I should make them immutable! Silver bullet, right? All my problems will go away. So I write a bunch of immutable beans.

Then I tried to serialize my immutable objects, and BAM, I hit this RFE: Serialize final fields. Turns out, its actually kind of hard to take an immutable object, vaporize it into a bunch of bits, and then reassemble those bits back into an immutable object on the other side. So I ended up with a bunch of objects that really, really wanted to be immutable but couldn't. Frustrating. Turns out that a "90% immutable object" just doesn't have the same feel to it.

Alright, so lesson learned (so I thought), moved on. Then I started working on a different project. Same type of deal, writing a bunch of new beans, want to make them immutable so I don't have to worry about whether or not that Person has a name. This time I'm working with JAX-WS, and again the serialization problem hits me right in the face. Ultimately I end up leaving my immutable beans alone, and writing a bunch of data transfer objects (similar to the immutable ones, but mutable). Then I could send those across and reassemble them into immutable versions on my own.

The saga continued when I made my way into JFace Data Binding. I had my Person with their name, age, height, weight, etc. I wanted to have a simple data entry form for a new Person. Problem is, with my immutable Person object, I basically have to set all those properties all at once, during construction. Stopped in my tracks again, since for data binding I basically need a standard Java bean with getters AND setters. Again I find myself writing intermediate objects which ultimately become their immutable counterparts.

The last part of the story came today, when I was poking around the p2 APIs. I was trying to see how the various properties of an IInstallableUnit got set. I find that there are no setters on the interface. Then I stumble across InstallableUnitDescription:

Once created, installable units are immutable. This description class allows a client to build up the state for an installable unit incrementally, and then finally product the resulting immutable unit.
A-ha! So I'm not the only one doing a bunch of intermediate stuff just to get to that final immutable object (pun intended).

So I put these question to you readers: How are you using immutable objects in your application? How about in your Eclipse applications? What lessons have you learned?

3 comments:

  1. I usually run into the same problem that you mentioned. I've settled with making at least all basic value objects immutable (objects that usually are represented as one or two fields: phone numbers, id codes, 2d vectors etc.)

    ReplyDelete
  2. When I need immutability, I use private non-final fields with only getters. Setters are not used.

    The serialization issue can be avoided in this way.

    ReplyDelete
  3. Try Item #78, Serialization Proxies, in Effective Java 2nd Edition.

    ReplyDelete