I like the notion behind the Null concept. Null does not mean anything. Null does not mean empty. Null means a reference to nothing but it’s still something between us. Null has the same effect on us that the black holes because it makes people think about it in different ways. Some people consider Null a good return value, some others consider it an error sign and more time you spend in the software industry more meanings you find.

To me Null it just like another constant value that it particularly warns about an undefined status. To me Null means “undefined” in the same manner that zero specify the smallest non negative number.  However cargo cult programmers have created funny definitions around it and Null has evolved to a design pattern. The following implementation shows a sample of the Null Object design pattern.

public abstract class PersonBase
{
public abstract string Name { get; }
public abstract int Age { get; }
public abstract void Talk();
public abstract void ShutUp();

static readonly NullPerson nullPerson = new NullPerson();

public static NullPerson Null
{
get { return nullPerson; }
}

// Embedded Null Object class
public class NullPerson : PersonBase
{
public override string Name { get { return string.Empty; } }
public override int Age { get { return 0; } }
public override void Talk() { }
public override void ShutUp() { }
}
}

As you can read in the previous code, NullPerson equals a valid Person aged 0, who can Talk and ShutUp but it prefers keeping silence and it’s named “” (just like the unspeakable). Some of the mentioned benefits of implementing the pattern are listed as follows:

  • Code is supposed to be cleaner and more concise.
  • Fewer null checks are supposed to be needed.
  • Less branching in the code is supposed to mean lower complexity.
  • Callers are supposed not needing to care whether they have a NullObject or a RealObject.

Imagine a real project like an email client using an implementation like previous one, after an end user empties the spam box a funny NullEmailMessage will pop up because the Null object is if fact a valid object and callers would treat it just like that, instead of showing a “There are no emails” message. Imagine a lift function displaying the floors in between, so if you are going from 5th floor to the 6th floor a funny NullLiftFloorMessage object will popup (displaying the 0th floor, and thus making end user enters in panic).

I guess is not necessary implementing the Null Object design pattern, in fact I think it is not a pattern. Just use it consistently in your code, so if you have a Find method returning Person instances and you prefer returning Null just do the necessary checking, it’s no a pain performing an if (result != null) statement. Don’t mix your domain concepts with your technical concepts, if you introduce a valid NullPerson definition then you have to contemplate its management all around your domain model.

From a technical point of view, the undefined status may appear in systems like databases because the Structural and integrity differences of the object-relational impedance mismatch, so a Boolean type can hold true, false and Null if you decide it. So, when designing your databases pay attention if columns can hold or nor Null values.

In a database context a Null object makes sense (see the DBNull and the Sql’s INullable interface), the same for value types (see the Nullable Types) but a NullPerson in your code unnecessary increases the complexity. By other hand if you use value types to implement status (like -1 to represent the dropdown list’s unselected index status or the string’s IndexOf not found status) first try to avoid using magic numbers or use them consistently if you have few status, otherwise go and consider all available options to represent domain status (not technical status).

[Update 09/19/2012:  another good example of a consistent use  of magic number is the Comparison delegate]

[Update 02/25/2013: I can not believe how some modern dynamic languages encourage their users to write code which mixes business domain concepts with technical concepts. The following anti-example brought into a higher level (or lower?) the the previous NullPerson anti-example by paying it the maximum salary representable by an integer:]

class NullJob extends Job { def salary = 0 }
people << new Person(name:'Harry', job:new NullJob())
biggestSalary = people.collect{ p -> p.job.salary }.max()
println biggestSalary

Cheers,

Javier Andrés Cáceres Alvis

Microsoft Most Valuable Professional – MVP
Intel Black Belt Software Developer