Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Attribution: This grew out of a related P.SE question

My background is in C / C++, but I have worked a fair amount in Java and am currently coding C#. Because of my C background, checking passed and returned pointers is second-hand, but I acknowledge it biases my point of view.

I recently saw mention of the Null Object Pattern where the idea is that an object is always returned. Normal case returns the expected, populated object and the error case returns empty object instead of a null pointer. The premise being that the calling function will always have some sort of object to access and therefore avoid null access memory violations.

  • So what are the pros / cons of a null check versus using the Null Object Pattern?

I can see cleaner calling code with the NOP, but I can also see where it would create hidden failures that don't otherwise get raised. I would rather have my application fail hard (aka an exception) while I'm developing it than have a silent mistake escape into the wild.

  • Can't the Null Object Pattern have similar problems as not performing a null check?

Many of the objects I have worked with hold objects or containers of their own. It seems like I would have to have a special case to guarantee all of the main object's containers had empty objects of their own. Seems like this could get ugly with multiple layers of nesting.

share|improve this question
    
Not the "error case" but "in all cases a valid object". –  user1249 Jun 8 '12 at 18:20
    
@ThorbjørnRavnAndersen - good point, and I edited the question to reflect that. Please let me know if I am still misstating NOP's premise. –  GlenH7 Jun 8 '12 at 18:44
3  
The short answer is that "null object pattern" is a misnomer. It's more accurately called the "null object anti-pattern". You're usually better off with an "error object" -- a valid object that implements the class' entire interface, but any use of it causes loud, sudden death. –  Jerry Coffin Jun 8 '12 at 18:52
1  
@JerryCoffin that case should be indicated by an exception. The idea is that you never can get a null and hence do not need to check for null. –  user1249 Jun 8 '12 at 19:55
1  
I dont like this "pattern". But possibly it is rooted in overconstrained relational databases, where it is easier to refer to special "null rows" in foreign keys during staging of editable data, before final update when all foreign keys are perfectly not null. –  user7071 Jun 9 '12 at 3:04

5 Answers 5

up vote 10 down vote accepted

You wouldn't use a Null Object Pattern in places where null (or Null Object) is returned because there was a catastrophic failure. In those places I would continue to return null. In some cases, if there's no recovery, you might as well crash because at least the crash dump will indicate exactly where the problem occurred. In such cases when you add your own error handling, you are still going to kill the process (again, I said for cases where there's no recovery) but your error handling will mask very important information that a crash dump would've provided.

Null Object Pattern is more for places where there's a default behavior that could be taken in a case where object isn't found. For example consider the following:

User* pUser = GetUser( "Bob" );

if( pUser )
{
    pUser->SetAddress( "123 Fake St." );
}

If you use NOP, you would write:

GetUser( "Bob" )->SetAddress( "123 Fake St." );

Note that this code's behavior is "if Bob exists, I want to update his address". Obviously if your application requires Bob to be present, you don't want to silently succeed. But there are cases where this type of behavior would be appropriate. And in those cases, doesn't NOP produce a much cleaner and concise code?

In places where you really can't live without Bob, I would have GetUser() throw an application exception (i.e. not access violation or anything like that) that would be handled at a higher level and would report general operation failure. In this case, there's no need for NOP but there's also no need to explicitly check for NULL. IMO, those checks for NULL, only make the code bigger and take away from readability. Check for NULL is still the right design choice for some interfaces, but not nearly as many as some people tend to think.

share|improve this answer
2  
Agree with the use case for null object patterns. But why return null when encountering catastrophic failures? Why not throw exceptions? –  Monster Truck Jun 9 '12 at 0:58
1  
@MonsterTruck: reverse that. When I write code, I make sure to validate majority of input received from external components. However, between internal classes if I write code such that a function of one class will never return NULL, then on the calling side I will not add null check just to "be more safe". The only way that value could possibly be NULL is if some catastrophic logic error occurred in my application. In that case, I want my program to crash exactly on that spot because then I get a nice crash dump file and reverse back the stack and object state to identify the logic error. –  DXM Jun 9 '12 at 6:05
    
@MonsterTruck: by "reverse that" I meant, don't explicitly return NULL when you identify catastrophic error, but expect NULL to only occur because of some unforeseen catastrophic error. –  DXM Jun 9 '12 at 6:09
    
I now understand what you meant by catastrophic error --something that causes the object allocation itself to fail. Right? Edit: Cannot do @ DXM because your nickname is just 3 chars long. –  Monster Truck Jun 9 '12 at 7:01
    
@MonsterTruck: weird about "@" thing. I know other people have done it before. I wonder if they tweaked the website recently. It doesn't have to be allocation. If I write a class and the intention of the API is to always return a valid object, then I wouldn't have the caller do a null check. But catastrophic error could be anything like programmer error (a typo that caused NULL to be returned), or maybe some race condition that erased an object before its time, or maybe some stack corruption. Essentially, any unexpected code path that led to NULL being returned. When that happens you want... –  DXM Jun 9 '12 at 7:18

So what are the pros / cons of a null check versus using the Null Object Pattern?

Pros

  • A null check is better since it solves more cases. Not all objects have a sane default or no-op behavior.
  • A null check is more solid. Even objects with sane defaults are used in places where the sane default isn't valid. Code should fail close to the root cause if it's going to fail. Code should fail obviously if it is going to fail.

Cons

  • Sane defaults usually result in cleaner code.
  • Sane defaults usually result in less catastrophic errors if they manage to get into the wild.

This last "pro" is the main differentiator (in my experience) as to when each should be applied. "Should the failure be noisy?". In some cases, you want a failure to be hard and immediate; if some scenario that should never happen somehow does. If a vital resource wasn't found... etc. In some cases, you're okay with a sane default since it's not really an error: getting a value from a dictionary, but the key is missing for example.

Like any other design decision, there are upsides and downsides depending on your needs.

share|improve this answer
1  
In Pros section: Agree with the first point. The second point is the designers fault because even null can be used where it shouldn't be. Does not say anything bad about the pattern just reflects on the developer who used the pattern incorrectly. –  Monster Truck Jun 9 '12 at 1:01
    
What is more catstrophic failure, not being able to send money or sending (and thus no longer having) money without recipient receiving them and not known it before explicit check? –  user470365 Sep 10 '12 at 15:27

I'm not a good source of objective information, but subjectively:

  • I don't want my system to die, ever; to me it's a sign of badly designed or incomplete system; complete system should handle all possible cases and never get into unexpected state; to achieve this I need to be explicit in modeling all the flows and situations; using nulls is not anyhow explicit and groups a lot of different cases under one umrella; I prefer NonExistingUser object to null, I prefer NaN to null, ... such approach allows me to be explicit about those situations and their handling in as much details as I want, while null leaves me with only null option; in such environment like Java any object can be null so why would you prefer to hide in that generic pool of cases also your specific case?
  • null implementations have drastically different behavior than object and are mostly glued to the set of all objects (why?why?why?); to me such drastical difference seems like a result of design of nulls to be indication of error in which case system most likely will die (I'm supprised so many people actually prefer their system to die in the above posts) unless explicitly handled; to me that's a flawed approach in it's root - it allows the system to die by default unless you explicitly have taken care about it, that's not very safe right? but in any case it makes impossible to write a code that treats the value null and object in same manner - only few basic built in operators (assign, equal, param, etc.) will work, all other code will just fail and you need two completely different paths;
  • using Null Object scales better - you can put as much information and structure into it as you want; NonExistingUser is a very good example - it can contain an email of the user you tried to recieve and suggest to create new user based on that information, while with the null solution I would need to think how to keep the email that people attempted to access close to the null result handling;

In environment like Java or C# it won't give you the main benefit of explicitness - safety of solution being complete, cause you can still recieve null in the place of any object in the system and Java has no means (except custom annotations for Beans, etc.) to guard you from that except explicit ifs. But in the system free of null implementaitons, approaching problem solution it in such a way (with objects representing exceptional cases) gives all the benefits mentioned. So try to read about something other than mainstream languages, and you'll find yourself changing your ways of coding.

In general Null/Error objects/return types is considered to be very solid error handling strategy and quite mathematically sound, while exceptions handling strategy of Java or C goes like only one step above "die ASAP" strategy - so basically leave all the burden of unstability and unpredictability of the system on developer or maintainer.

There are also monads that can be considered superior to this strategy (also superior in complexity of understanding at first), but those are more about the cases when you need to model external aspects of type, while Null Object models internal aspects. So NonExistingUser is probably better modeled as monad maybe_existing.

And lastly I don't think that there is any connection between Null Object pattern and silently handling error situations. It should be other way around - it should force you to model each and every error case explicitly and handle it accordingly. Now of course you might decide to be sloppy (for what ever reason) and skip handling the error case explicitly but handle it generically - well that was your explicit choice.

share|improve this answer
1  
The reason I like my application to fail when something unexpected happens is - that something unexpected happened. How did it happen? Why? I get a crash dump and I can investigate and fix a potentially dangerous issue, rather than let it get hidden in the code. In C#, I can of course catch all unexpected exceptions to try and recover the application, but even then I want to log the place where the problem happened and find out if it's something that needs separate handling (even if it is "don't log this error, it's actually expected and recoverable"). –  Luaan Nov 27 '13 at 11:19

I think it's interesting to note that the viability of a Null Object seems to be a little different depending on whether or not your language is statically typed. Ruby is a language that implements an object for Null (or Nil in the language's terminology).

Instead of getting back a pointer to uninitialized memory, the language will return the object Nil. This is facilitated by the fact that the language is dynamically typed. A function isn't guaranteed to always return an int. It can return Nil if that's what it needs to do. It becomes more convoluted and difficult to do this in a statically typed language, because you naturally expect null to be applicable to any object that can be called by reference. You'd have to start implementing null versions of any object that could be null (or go the Scala/Haskell route and have some kind of "Maybe" wrapper).

MrLister brought up the fact that in C++ you're not guaranteed to have an initialize reference/pointer when you first create it. By having a dedicated null object instead of a raw null pointer, you can get some nice additional features. Ruby's Nil includes a to_s (toString) function that results in blank text. This is great if you don't mind getting a null return on a string, and want to skip reporting it without crashing. Open Classes also allow you to manually override the output of Nil if need be.

Granted this can all be taken with a grain of salt. I believe that in a dynamic language, the null object can be a great convenience when used correctly. Unfortunately, getting the most out of it might require you to edit it's base functionality, which could make your program hard to understand and maintain for people used to working with its more standard forms.

share|improve this answer

For some additional viewpoint, have a look at Objective-C, where instead of having a Null object the value nil kind-of works like an object. Any message sent to a nil object has no effect and returns a value of 0 / 0.0 / NO (false) / NULL / nil, whatever the return value type of the method is. This is used as a very pervasive pattern in MacOS X and iOS programming, and usually methods will be designed so that a nil object returning 0 is a reasonable result.

For example, if you want to check whether a string has one or more characters, you could write

aString.length > 0

and get a reasonable result if aString == nil, because a non-existing string doesn't contain any characters. People tend to take a while to get used to it, but it would probably take me a while to get used to checking for nil values everywhere in other languages.

(There's also a singleton object of class NSNull which behaves quite different and isn't used very much in practice).

share|improve this answer
    
Objective-C made the Null Object/Null Pointer thing really blurry. nil get #define'd to NULL and behaves like a null object. That is a runtime feature while in C#/Java null pointers emits errors. –  Maxthon Chan May 2 at 17:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.