Tuesday, 23 May 2006

Immutable POJOs - Improving on getters/setters

So we all know the bean/POJO get/set convention right? Its fine for mutable objects, but what about immutables? The convention just doesn't work there.

BigDecimal base = new BigDecimal(100d);
base.setScale(2);  // BUG!!!

Why is the above a bug? Because BigDecimal is immutable, and so the set method doesn't actually change base. Instead, the method returns a new BigDecimal instance which isn't being assigned in the example. Here's the fixed version:

BigDecimal base = new BigDecimal(100d);
base = base.setScale(2);  // FIXED by assigning

In addition, by returning a new instance, the set method actually breaks the JavaBean spec. This is because the JavaBean spec says that set methods must return void.

So what can be done? Well I'd like to argue that the time has come for a new coding convention for immutable beans/POJOs. As a convention (preferably Sun endorsed) it would allow frameworks like JSF or Struts to handle immutable objects properly. So, what do I propose?

Mutable verb   Immutable verb
get get
set with
add plus
subtract minus

Here's an example of a datetime object using these conventions:

DateTime dt = new DateTime();

// immutable get is the same as a mutable get
int month = dt.getMonthOfYear();

// immutable sets use the 'with' verb
dt = dt.withYear(2006);
dt = dt.withMonthOfYear(5);
dt = dt.withDayOfMonth(23);

// immutable add or subtract using the 'plus'/'minus' verbs
dt = dt.plusYears(1);
dt = dt.minusDays(1);

// combinations, for example, the first day of the next month
dt = dt.withDayOfMonth(1).plusMonths(1);

If adopted as a standard, there is even the potential to write a PMD or FindBugs rule to match on the verbs and ensure that you actually assign the result, thus eliminating a potential bug.

So, do you use immutable objects? Do you have a coding convention like this? Should this become a Sun convention? Opinions welcome!