Instances of the null object must have the same interface as the objects they're replacing.
In a statically typed language, this means that they must inherit from the same base class (C++) or implement the same interface (Java or COM) as the "real" objects they replace.
In a dynamically typed language the NullObject just has to respond sensibly to the same messages as the "real" objects.
In SmalltalkLanguage, you could define #doesNotUnderstand for nil so that it always returns itself. A bit of thought will reveal why this is indeed a sensible return value for every possible message sent to a "real" object. As a consequence, you could use nil as a null object for everything. Think about it; one null object that works everywhere and in every circumstance. Beats having to define a new null object class for every single bloody class in your code, don't it?
Unfortunately, redefining nil's behaviour would break a lot of existing Smalltalk code which relies on nil to throw an exception upon receipt of #doesNotUnderstand. And even if there weren't all of that code to break, it would still be a bad implementation of a null object since nil is incapable of telling you which method first invoked it.
But these problems aren't insoluble. What you do is create a class Null that does the same thing, but also keeps track of the sender of the instantiation message.
http://www.smalltalkpro.com/general.html provides a detailed overview of null objects, especially as they were used in ObjectiveCee. It also provides fileIn code for a Smalltalk implementation of Null.
How do you know that you have a null object?
Answer #1: Why do you care? You DON'T. And that's precisely why you're using the null object in the first place.
Say you're traversing a tree and you ask a null object for its children. You get back a null object. Then you ask it to iterate a block over all of them and again it does nothing, just returning itself. Eventually, when you get tired of processing this imaginary node, you move on to other nodes in the tree. This is exactly the behaviour you want, and you never needed to know whether something was a "real" object or a null object. It never mattered.
But say you're curious, so just for the hell of it...
Answer #2: If the null is a singleton, check for "object identity being equal."
Nulls are often implemented using the SingletonPattern, as they typically have no instance variables, no instance-specific behavior, and most people think there's no need to differentiate between different instances of "nothing in particular".
Answer #3: Use an "are you null?" method call, or a type test such as Visitor (NullObjectAndVisitor) or dynamic_cas<>.
(Type tests can use a TagInterface if the null object does not already have its own type/class.)
See "Shape" example by NatPryce in the NullObjectDiscussion.
How many null object classes should there be?
As few as you can get away with. In Smalltalk, that's 1.
And, using the SingletonPattern with this, you could have a single null instance to serve the needs of all clients.
But, this is NOT a fundamental requirement of the null object pattern. And of course, many languages make it impossible to implement a sane general null. Moreover, using a generalized null object for, say, the GUI can have drawbacks.
So, one typically implements a different null object class for each interface / base object that needs it. Like, you'd have one null class (and instance) as a placeholder for Shape objects, and a different class as your NullLayoutManager? - a strategy for GUI tool layout (that doesn't move anything).
See also comments by NatPryce in the NullObjectDiscussion. (...where he suggests having multiple NullObject classes.)
A null object must be immutable
If you can change the state of a null in a way that can be detected by clients, it is not a null.
A function of a null object should return a null object
If a method of a null's interface must return another object, it should return a null associated with that particular object class, not a null reference. For example, if a method is defined as returning a collection of objects, the null should return an empty collection. And if a method is defined as returning an iterator, the null should return an iterator that is at the end of its sequence, and so on.
This is trivial if you have a generalized null. Just have all of the methods return self. And of course, if all methods behave in exactly the same way then you don't even need to implement them. Just define #doesNotUnderstand to return self. Oh the joys of Smalltalk.
In Java, and any other strongly typed language, I believe you'll need to think carefully about whether a particular null should implement "equals" and "hashCode", and what those implementations should be. Multiple inheritance (of the interface shared between a FooNullObject? and Foo) may help here. I think the question that can become (no pun intended) dicey is what value should be returned by the following:
FooNullObject? theFooNullObject = FooNullObject?.theInstance(); BarNullObject? theBarNullObject = BarNullObject?.theInstance(); theFooNullObject.equals(theBarNullObject);In the above example, I think the method should either return false or throw either an IllegalArgumentException or a ClassCastException. It is like asking "Is a shape that has no area equal or not equal to an array with no elements?" (to take two examples from the discussions about this pattern). The question just doesn't make sense. Unfortunately Java doesn't allow us to catch this kind of type error at compile time, and so we have to either return false (as almost all classes do when a different type is passed to their equals method) or throw a runtime exception to indicate that a programming error occurred. -- NatPryce
TomStambaugh replies: The question certainly "makes sense" in a context of, for example, some sort of inspector that is doing a traversal of the contents of, for example, a heterogeneous collection. So "false" is a perfectly reasonable answer -- except that often the developer is trying to say something like "are you empty?". The practical reality is that a predicate that began as something like
if (anObject == null) { // do something interesting }will, over time, grow into something like:
if (anObject.equals(theFooNullObject) || anObject.equals(theBarNullObject)) { //do something interesting }Not only is this bloated, but it needs be changed when some class Zee, with its ZeeNullObject?, is added.
I suppose we could do something cleaner, like define "isNull" on each NullObject implementation. Then, this code becomes:
if (anObject.isNullObject()) { //do something interesting }which I like.
I have recently come across this issue with the null object pattern (see NullObjectAndRefactoring). My opinion is that if application code needs to check whether it is using a NullObject or not, then the system is no longer using the null object pattern at all, because the NullObject class has been "promoted" from being a mere implementation detail to being a concept in the application domain. The intent of the null object pattern is to remove checks like those above from code that traverses a recursive data structure. If it doesn't, one isn't using the null object pattern and should refactor one's design or at least rename the null object classes. -- NatPryce
So "false" is a perfectly reasonable answer -- except that often the developer is trying to say something like "are you empty?". - If that's what we are trying to ask, then we want an isEmpty() method. The null object would implement it to always return true.
IsNullObject() as not a good way to detect empty objects. It's essentially a type-test, and type-tests are usually dubious. They risk confusing domains. An aim of null object is to replace type-tests with polymorphic dispatch. -- DaveHarris
Why would anyone care whether a null object is empty or not? One doesn't. At least, not if one's using a properly message-eating null.
See NullObjectDiscussion for more.
I don't know where to put this other then here (contextually). NullObjectDiscussion is just too big and doesn't seem to fit there. Move it if you like:
In a Java framework I once built before I knew of the null object pattern, I defined a Null interface and some implementations as described above. And I decided to let the equals()-method return true if passed a null reference. Example:
public boolean equals(Object obj) { return obj == null; }so the following test would always detect nulls without recurse to the implementing classes:
if (anObject == null || anObject.equals(null)) { //do something interesting }The initial motivation for this class was to get rid of these useless NullPointerExceptions, that occurred if somewhere a 'null' was returned, not handled (as it should be) and passed on and on, until sometime later the NPE was thrown and nobody knew why.
I decided to let the Null object (explicitly no singleton) know where and why it was created by storing an exception on its creation. This exception was then used on method calls, that could not produce trivial results (empty collections etc. as above) to throw a NPE, that had as the ultimate cause the stored exception. This way these common and hard to detect error cases were easily locatable.
I know, that this makes these Null objects less useful, as creating the stored exception has undefined timing, but in my application, this was acceptable. An alternative would be, to provide some Object or String as "cause".
Wow, I really really really like this! Thanks, Gunnar! -- AdamBerger
The implementation of NullObject has been coined DeferredExceptionObject.
In jumping to the NullObjectImplementation, I fear we have jumped over a fundamental question that was never answered in the context of the java type system. While this was debated at length in NullObjectDiscussion, I don't think that discussion ever came to a consensus.
Suppose I am writing a method that returns the current selection of a list widget, where the list widget controls a list of instances of class Foobar.
If I understand the null object pattern correctly, the advocates of null object suggest that the return type of the method should be "Foobar", and that it should return a value of "NullFoobar?" when called on an empty list (as opposed to, for instance, raising an exception).
Presumably, the same method on a list widget that controls a list of instances of class Mumble would have a similar method whose return type would be "Mumble", and that method should return an instance of "NullMumble?" when called on an empty list.
Now, I have to write a method that does something to handle the situation where there is no selection in both the Foobar and the Mumble lists.
If I understand the NullObjectImplementation correctly, I have several choices:
The fundamental issue, as I see it, is that NullFoobar? is not the same object as NullMumble? -- and yet in a host of important ways, we expect NullFoobar? and NullMumble? to behave as if they are identical. This is the sense in which they are similar to Lisp's "Nil", which is both atom and list. NullMumble? is both empty and a Mumble. NullFoobar? is both empty and a Foobar. The aspects of being "empty" are surely common to all Null<Whatever> classes. The aspects of being "Foobar" or "Mumble" are surely unique to NullFoobar? and NullMumble?.
In short -- in a strongly-typed system such as Java (which has, to my knowledge, no compiler support to distinguish the type "Foobar" from the type "FoobarOrNull?"), this pattern simply moves complexity from one place to another. Specifically, like contemplating the role of "zero" in a number system, the attempt to instantiate the absence-of-a-value (or any other way I try to talk myself into the same quantity) creates a singularity in a strongly-typed system like Java -- and the null object pattern exacerbates that singularity. I suggest that in a java-style strongly-typed system, null object is an AntiPattern -- TomStambaugh
I think this is a very well-thought answer and I share Tom's reluctance to follow that path (because it "moves complexity from one place to the other"). One of the pages leading to here is NullPointerException which more or less originated from the fact that it - sometimes - may be difficult to find the original source of the problem finally leading to the exception. (You have to find where null was assigned and/or why null is still in an object reference that should be valid). But instead of adding more unit tests to reveal the problem where it originated, I can see hordes of programmers now move on to replace null-s with NullObject-s in code that runs well, creating new kinds of problems and deficiencies. It's much like with the (in)famous SingletonPattern: A perfectly well solution for a PROBLEM, but no argument NOT using globals where they work perfectly. (Sorry, I recently had to work with code that used Singletons over and over were simple globals would have fit the purpose perfectly, because NOT ONE of the forces that demand singletons was to resolve.) Considering Tom's remarks in the light of the SimplestThingThatCouldPossiblyWork makes me very reluctant to recommend to use NullObjects (at least in Java). Maybe it's better to invest more time in creating unit tests around the origins of possible NullPointerExceptions.
Unfortunately, it's the wrong answer. It's the wrong answer because Tom writes:
"I have to write a method that does something to handle the situation where there is no selection in both the Foobar and the Mumble lists."
Which of course is the antithesis of the null object pattern which is based on the idea that you don't care about the null. Apparently, Tom doesn't understand the point of the null object pattern and is trying to force fit it into a situation where it simply doesn't belong. Either that, or he doesn't understand the point of the null object pattern and is writing really crummy code that doesn't take advantage of it.
And since you're agreeing with him, I'm pretty sure you don't get it either. Which puts a wickedly ironic spin to your complaint that there'll be hordes of programmers who don't get null object and misapply it. Are you speaking of yourself? -- RichardKulisz(?)
Probably true. The original papers on NullObject (as opposed to the Wiki pages, which have kinda bastardized the concept) all say that it's an object that "does nothing". There are not many conceivable behaviors that "do nothing". It's usually limited to returning a null value of some particular type ("", 0, NULL, etc.) So if you're using NullObject where it's supposed to be used, you won't need to worry about duplicating non-trivial behavior, because it's all trivial.
Tom's problem is that several Java programmers use null (and later NullObject) as a means of in-band signalling when you need "just one more" possible value. I've even seen one of the creators of the Java language do this in design discussions. In this case, you do need special and possibly non-trivial code to handle each case, and it needs to be dispersed through several if(object == null) tests within clients. But I've got a bunch of possible suggestions that could fix Tom's problem.
-- JonathanTangFor a different take see NullConsideredHarmful. See also JavaTypingWasSimple and NiceLanguage.
See JavaNullProxy
In JavaLanguage, at least, a NullObjectImplementation is much easier if you apply the LawOfDemeter and its stronger cousin TellDontAsk. I suspect this is true of other languages as well. -- MarkAddleman
For what it is worth, here is a PythonLanguage implementation
class Null: 'Null object pattern implementation' def __getattr__(self, name): 'return self for any attribute' return self def __call__(self, *args, **kwargs): 'return self when called with any arguments' return self def __str__(self): 'cosmetic display of the object' return "<Null Object>"-- AlexandreFayolle?