Null Considered...Harmful? Awful? Annoying?

I heard about this upcoming presentation about Hoare's "1 billion dollar mistake". Now, I'm not a lawyer, so I don't know if his "confession" means he has to pay damages to developers (I kid, I kid!), but I was surprised that he thought the concept of null was such a bad, bad idea.

However, the more I thought about it, the more the idea resonanted with me.

I mean, I'm always decorating my methods like this:

public void DoSomethingAwesome(TimeMachine machine)
{
   if(machine == null)
   {
      throw new ArgumentNullException("machine");
   }
}

Nulls always seem like a hinderance. I really don't want to ever do anything to a null reference, because the program will crash and burn badly.

So can we really get rid of them in code?

We, we can ensure code crashes when it sees a null reference from a parameter reference. That's easy. But...what about factory methods? Like this:

var customer = CustomerFactory.Find(1234);

if(customer != null)
{
   // Do something interesting with the customer...
}

This is something I see all the time. In some cases, if a factory method cannot produce whatever it's trying to return, it's an error and an exception should be thrown. But in other cases, you're trying to find one specific item, like a customer. So returning null seems like a natural choice if the customer can't be found - I'd personally find it weird if the method threw CustomerNotFoundException.

But maybe we can repurpose the method like this:

var customer = Customer.Find(1234);

if(customer.Count > 0)
{
   // Pull out the customer and do something with it...
}

In other words, you return a collection. This seems like a better approach. Either you find 0, 1 or more than one. This also makes the API more consistent if you have overloads of the method that could return more than 1 customer:

var customer = Customer.Find("Joe", "Smith");

if(customer.Count > 0)
{
   // Pull out the customers and do something with them...
}

The convention with returning collections in .NET is that they should always be non-null, and the assumption would be that the collection only contains non-null references.

Of course, one could argue that a null check might be cheaper from an execution perspective than it would be to create a collection-like object, return it, and read the Count property. That's hard to say without doing some performance analysis, and like any performance optimizations, don't do them prematurely and don't guess. I ran some very simple tests comparing the collection return vs. null return check, and the null check is faster by about 37%. But that's just one test, and frankly, compared the rest of a large system, is that really that big of a deal? I could run my collection test code 5 million times in just over 1 second, and the null test code in 0.68 seconds. The gain with a non-null API seems better in my opinion.

Overall, I'm still not convinced that nulls rank up there with the evilness that gotos are (I'm also half-joking here). But I have to admit, I do find them annoying. The more I code, the more I try to follow more modern conventions (e.g. immutability, composition over inheritance, etc.). And writing code that doesn't tolerate null is slowly working itself into my approach.

What do you think? Is null a huge mistake? Should it be banished? Or are there actually valid uses for that 4-letter word?

* Posted at 01.23.2009 08:30:07 AM (Last Update: 01.26.2009 08:37:43 AM) | 4 comments | Link | RSS *

Comments

# linq can help..., from Justin Chase at 01.23.2009 06:11:22 PM

You don't really need to use the Count property if you're going to do something with all customers, just go right to the foreach. If you really need to know if there are more than 0 you can use the linq method Any().

I don't think you want to actually get rid of nulls though, null is legit. Suppose you used a non-nullable complex object as an incoming parameter, instead of just validating the null condition you now need to validate the entire state of the object. How can you tell the difference between default and non-existant without null?

Null checks on parameters could be easier with meta programming such as in boo:

def DoSomethingAwesome([required] machine as TimeMachine):
pass

But I think the real point is that it is important to throw an exception in this case because your app is in an invalid state and you want to fail early. If you just accept some default object you need to now evaluate the entire object for validity or you run the risk of continuing too far beyond the beginning of the invalid state before failing which can be extremely difficult to debug.

Also, nulls make lazy loading easy.

# ., from Edison at 01.24.2009 01:17:29 PM

I agree with the collection that we should always create a non-null instance, because I don't want to check for null before I iterate them in foreach or for loop.
On the other hand, for a non collection (i.e: an instance of Employee object), I would rather use a null check.

private void PersistEmployee (Employee employee)
{
if (employee == null)
return;
// Persist employee into database
}

# Comments, from Jason Bock at 01.25.2009 11:26:42 AM

Edison,

In that case, I'd throw an ArgumentNullException. I'm not saying you can never check for null (esp. in public APIs) but in this case it's better to throw.

Justin,

Whether I check for Count or go into foreach isn't the point.

Code Contracts will make such DBC rules language-independent.

Why not use a boolean to do lazy loading rather than a check for null? I'm not saying this is a better approach, but it does eliminate the use of a null check.

# Hoare knew the right answer at the time..., from Daniel Earwicker at 01.26.2009 08:37:40 AM

As he says "More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965."

Another way of coping with nulls is to follow the Maybe monad pattern:

http://incrediblejourneysintotheknown.blogspot.com/2008/12/maybe-monad-in-c.html

Add a Comment

(*) = Required field
Name (*):

E-Mail (*):

Web Site:

Title (*):

Comments (*):

Enter the code you see (*)



Quote
"If you read John Milton's Paradise Lost you will find that his Heaven is described as an eternal sing-along of praise to God. It is no wonder that one-third of the angels rebelled." Isaac Asimov
Twitter History
follow me on Twitter
Blog History