Tuesday, October 03, 2006

Defensive Programming: Handling Nulls

C was one of the first languages I learned to program in. In C, you access memory direcly with pointers and it's not unusual for bugs to arise from improperly dereferencing those pointers. This generally causes the application to crash, often with a segmentation fault or bus error, and sometimes the application manages to carry on, overwriting memory until it finally fails, often in a way that is very difficult to reproduce or track down. Accessing memory directly certainly gives the maximum amount of control, but it's also very error-prone. In managed/interpreted environments, like Java, C#, Perl, Python, or Ruby, one can't access memory directly. Instead, the runtime environment interposes a handle to an object or structure. This prevents most of the memory problems that arise in C applications. However, there is still the problem of using references that don't point to any particular object. These are called null references, or nil references, or something along those lines. In Java, when you call a method on a reference that doesn't point to any object, the runtime throws a NullPointerException. I'd rather it throw something like a NullReferenceException, but that's neither here not there :). It's not nearly as bad as having memory problems in C, because you can trap these exceptions and then your application can carry on, but it doesn't improve user confidence, and it leaves parts of the application inaccessible to the user.

One of the ways to handle such exceptions is called the Null Object pattern. basically, the idea is to guarantee that a reference to a particular kind of object will always be initialized with a stub that implements some kind of harmless do-nothing behaviour for that type of object. The idea is to guarantee that an object will always be there when you call a method on an object reference. Let's say your application involves keeping track of customers. If you search for a customer with an invalid id, instead of returning null, you'd get back a Customer object. If you try to call any methods on this object, they will either do nothing or return intelligent defaults. For example, getAge() would return 0. This is a useful pattern, but there are some issues to keep in mind. First of all, there will always be cases where one must distinguish between a real object and a null object stub. This is generally done by implementing an isNull method for all domain objects (in Java, you could create a Substitutable interface for this purpose). This isNull method will only return true when executed on Null objects. Secondly, defining the proper do-nothing behaviour for complex domain objects can lead to overhead. In an example below, I will try to show an what might need to be done to rigorously implement Null Object. Also, If you want to use the Null Object pattern, you should adhere to the Law Of Demeter to avoid having to implement a whole bunch of un-necessary Null Object types. In other words, instead of having something like student.findExam(3).getGrade(), you would simply call student.getGradeForExam(3). This approach makes the Student class easier to turn into a Null Object. If you tend to be checking object.isNull all the time, then maybe this pattern is not the right one to use, since it is designed for cases where most of the time, you are ok with the Null Object's default behaviour. Finally, I'm not sure it's possible to always define proper do-nothing behaviour that won't depend on some context, though I can't think of a real case of this problem at the moment.

Here is an example I've tried to cook up to show what Null object implemented
throughout an application might look like (it's Java code, as usual, since that's
the language I feel most comfortable with).

public interface Substitutable {
public boolean isNull();
}

public abstract class NullObject implements Substitutable {
public boolean isNull() {
return true;
}

public boolean equals() {
return false;
}
}

public abstract class DomainEntity implements Substitutable {
public boolean isNull() {
return false;
}
}

public interface Customer {
public String getName();
public void setName(String name);
}

public class CustomerImpl extends DomainEntity implements Customer {
public String getName() {
return name;
}

public void setName(String aName) {
name = aName;
}
}

public class NullCustomer extends NullObject implements Customer {
public String getName() {
return "";
}

public void setName(String s) {}
}


Note the extra overhead of an interface for each domain class needed (at least in my example) to more easily support NullObject. To introduce methods in Customer that return proper domain entities rather than value objects like String, I'd have to provide NullObject support for those as well! Also, I've implemented default behavour for equals method to always return false. I wonder that the right behaviour for hashCode might be. Hmmm. It's definitely a bit of extra work. Is it worth it? I haven't ever tried this approach so I'm not really sure.

While the Null Object pattern can be helpful in eliminating null exceptions, it has to be implemtented judiciously throughout an application. Another approach I tend to use to prevent having to check for nulls all over the place, which I haven't seen on too many other projects, is to write static utility methods for many standard operations that compare two objects in some way. For example, one often finds code like if (a != null and a.equals(b)) - I suggest replacing that with if (Util.equal(a,b)). Here is how I implement the Util.equal method:
 public static boolean equal(Object a, Object b) {
if (a == null || b == null)
return false;
return a.equals(b);
}
Again, if a were a Null Object, it would implement the equals method by just returning false.

Other ideas include numeric comparisons on non-primitive numeric types, e.g. isZero(Number a), isLessThan(Number a, Number b), etc..., date comparisons, and so on.

No comments: