Content deleted Content added
m Disambiguated: Martin Fowler → Martin Fowler (software engineer) |
m Disambiguating links to Object-orientation (link changed to Object-oriented programming) using DisamAssist. |
||
(46 intermediate revisions by 30 users not shown) | |||
Line 1:
{{Short description|Object with no referenced value or with defined neutral ("null") behavior}}
{{Redirect|Null object|the concept in category theory|Initial object}}
In [[Object-oriented programming|object-oriented]] [[computer programming]], a '''null object''' is an [[Object (computer science)|object]] with no referenced value or with defined neutral (
| first = Thomas
| last = Kühne
| contribution = Void Value
| title = Proceedings of the First International Conference on Object-Oriented Technology, White Object-Oriented Nights 1996 (WOON'96), St. Petersburg, Russia
| year = 1996
}}</ref> ▼
and later in the [[Pattern Languages of Programs#Publications|''Pattern Languages of Program Design'' book series]] as "Null Object".<ref>{{Cite book
| first = Bobby
| last = Woolf
Line 13 ⟶ 21:
| year = 1998
| publisher = Addison-Wesley
}}</ref>
▲}}</ref>
==Motivation==
In most object-oriented languages, such as [[Java (programming language)|Java]] or [[C Sharp (programming language)|C#]], [[Reference (computer science)|references]] may be [[Null pointer|null]]. These references need to be checked to ensure they are not null before invoking any [[Method (computer science)|methods]], because methods typically cannot be invoked on null references.
The [[Objective-C|Objective-C language]] takes another approach to this problem and does nothing when sending a message to <code>nil</code>; if a return value is expected, <code>nil</code> (for objects), 0 (for numeric values), <code>NO</code> (for <code>BOOL</code> values), or a struct (for struct types) with all its members initialised to <code>null</code>/0/<code>NO</code>/zero-initialised struct is returned.<ref>{{Cite web|url = https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithObjects/WorkingwithObjects.html#//apple_ref/doc/uid/TP40011210-CH4-SW22|title = Working with Objects (Working with nil)|date = 2012-12-13|
== Description ==
{{Unreferenced section|date=June 2023}}
Instead of using a [[null reference]] to convey the absence of an object (for instance, a non-existent customer), one uses an object which implements the expected [[Interface_(computing)#In_object-oriented_languages | interface]], but whose method body is empty.
One advantage of this approach over a working default implementation is that a null object is very predictable and has no side effects: it does ''nothing''.
For example, a function may retrieve a list of files in a folder and perform some action on each. In the case of an empty folder, one response may be to throw an exception or return a null reference rather than a list. Thus, the code
By returning a null object (i.e., an empty list) instead, there is no need to verify that the return value is in fact a list. The calling function may simply iterate the list as normal, effectively doing nothing. It is, however, still possible to check whether the return value is a null object (an empty list) and react differently if desired.
The null object pattern can also be used to act as a stub for testing, if a certain feature such as a database is not available for testing.
Line 35 ⟶ 44:
'''class''' node {
node left
node right
}
Line 42 ⟶ 51:
'''function''' tree_size(node) {
return 1 + tree_size(node.left) + tree_size(node.right)
}
Line 48 ⟶ 57:
'''function''' tree_size(node) {
set sum = 1
'''if''' node.left exists {
sum = sum + tree_size(node.left)
}
'''if''' node.right exists {
sum = sum + tree_size(node.right)
}
return sum
}
This, however, makes the procedure more complicated by mixing boundary checks with normal logic, and it becomes harder to read. Using the null object pattern, one can create a special version of the procedure but only for null nodes:
'''function''' tree_size(node) {
return 1 + tree_size(node.left) + tree_size(node.right)
}
'''function''' tree_size(null_node) {
return 0
}
This separates normal logic from special case handling
==Relation to other patterns==
It can be regarded as a special case of the [[State pattern]] and the [[Strategy pattern]].
It is not a pattern from ''[[
| first = Martin
| last = Fowler
|
| year = 1999
| title = Refactoring. Improving the Design of Existing Code
| publisher = Addison-Wesley
| isbn = 0-201-48567-2
| url-access = registration
}}</ref> and Joshua Kerievsky's Refactoring To Patterns<ref>{{cite book▼
| url = https://archive.org/details/isbn_9780201485677
▲ }}</ref> and Joshua Kerievsky's Refactoring To Patterns<ref>{{cite book
| first = Joshua
| last = Kerievsky
|
| year = 2004
| title = Refactoring To Patterns
Line 94 ⟶ 105:
| first = Robert
| last = Martin
|
| year = 2002
| title = Agile Software Development: Principles, Patterns and Practices
| publisher = Pearson Education
| isbn = 0-13-597444-5
| url-access = registration
}}</ref> is dedicated to the pattern.▼
| url = https://archive.org/details/agilesoftwaredev00robe
▲ }}</ref> is dedicated to the pattern.
==Alternatives==
From C# 6.0 it is possible to use the "?." operator (aka [[Safe_navigation_operator#C.23|null-conditional operator]]), which will simply evaluate to null if its left operand is null.
<
// compile as Console Application, requires C# 6.0 or higher
using System;
Line 121 ⟶ 134:
// The output will be:
// 4
</syntaxhighlight>
===Extension methods and Null coalescing===
{{Unreferenced section|date=June 2023}}
In some [[Microsoft .NET]] languages, [[Extension method]]s can be used to perform what is called 'null coalescing'. This is because extension methods can be called on null values as if it concerns an 'instance method invocation' while in fact extension methods are static. Extension methods can be made to check for null values, thereby freeing code that uses them from ever having to do so. Note that the example below uses the [[C Sharp (programming language)|C#]] [[Null coalescing operator]] to guarantee error free invocation, where it could also have used a more mundane if...then...else. The following example only works when you do not care the existence of null, or you treat null and empty string the same. The assumption may not hold in other applications.
<
// compile as Console Application, requires C# 3.0 or higher
using System;
Line 148 ⟶ 162:
// The output will be:
// 18
</syntaxhighlight>
==In various languages==
Line 158 ⟶ 172:
A language with statically typed references to objects illustrates how the null object becomes a more complicated pattern:
<
import std;
class animal ▼
{▼
public:
virtual void make_sound() const = 0;▼
virtual ~Animal() = default;
};
class
public:
{▼
virtual void
{ ▼
}▼
};
class
public:
virtual void
};
</syntaxhighlight>
Here, the idea is that there are situations where a pointer or reference to an <code>
The null object pattern solves this problem by providing a special <code>
The special null class must be created for each class hierarchy that is to have a null object, since a <code>
Note
<
//
void DoSomething(const Animal& animal) {
}
//
void
//
}
</syntaxhighlight>
===C#===
Line 204 ⟶ 217:
C# is a language in which the null object pattern can be properly implemented. This example shows animal objects that display sounds and a NullAnimal instance used in place of the C# null keyword. The null object provides consistent behaviour and prevents a runtime null reference exception that would occur if the C# null keyword were used instead.
<
/* Null object pattern implementation:
*/
Line 233 ⟶ 246:
// Dog is a real animal.
class Dog :
{
public override void MakeSound()
{
Console.WriteLine("Woof!");
Line 258 ⟶ 271:
unknown.MakeSound(); // outputs nothing, but does not throw a runtime exception
}
}</
===Smalltalk===
Line 264 ⟶ 277:
Following the Smalltalk principle, ''everything is an object'', the absence of an object is itself modeled by an object, called <code>nil</code>. In the GNU Smalltalk for example, the class of <code>nil</code> is <code>UndefinedObject</code>, a direct descendant of <code>Object</code>.
Any operation that fails to return a sensible object for its purpose may return <code>nil</code> instead, thus avoiding the special case of returning "no object" unsupported by Smalltalk designers. This method has the advantage of simplicity (no need for a special case) over the classical "null" or "no object" or "null reference" approach. Especially useful messages to be used with <code>nil</code> are <code>isNil</code>, <code>ifNil:</code> or <code>
===Common Lisp===
Line 278 ⟶ 291:
In Common Lisp, the object <code>nil</code> is the one and only instance of the special class <code>null</code>. What this means is that a method can be specialized to the <code>null</code> class, thereby implementing the null design pattern. Which is to say, it is essentially built into the object system:
<
;; empty dog class
Line 292 ⟶ 305:
;; innocuous empty body: nil makes no sound.
(defmethod make-sound ((obj null)))
</syntaxhighlight>
The class <code>null</code> is a subclass of the <code>symbol</code> class, because <code>nil</code> is a symbol.
Since <code>nil</code> also represents the empty list, <code>null</code> is a subclass of the <code>list</code> class, too. Methods parameters specialized to <code>symbol</code> or <code>list</code> will thus take a <code>nil</code> argument. Of course, a <code>null</code> specialization can still be defined which is a more specific match for <code>nil</code>.
Line 300 ⟶ 313:
Unlike Common Lisp, and many dialects of Lisp, the Scheme dialect does not have a nil value which works this way; the functions <code>car</code> and <code>cdr</code> may not be applied to an empty list; Scheme application code therefore has to use the <code>empty?</code> or <code>pair?</code> predicate functions to sidestep this situation, even in situations where very similar Lisp would not need to distinguish the empty and non-empty cases thanks to the behavior of <code>nil</code>.
===
In [[Duck typing|duck-typed]] languages like [[Ruby (programming language)|Ruby]], language inheritance is not necessary to provide expected behavior.
<
def get_animal(animal=NilAnimal.new)
Line 322 ⟶ 335:
get_animal.sound
=> nil
</syntaxhighlight>
Attempts to directly [[
===
In [[Duck typing|duck-typed]] languages like [[JavaScript]], language inheritance is not necessary to provide expected behavior.
<
class Dog {
sound() {
Line 346 ⟶ 359:
['dog', null].map((animal) => getAnimal(animal).sound());
// Returns ["bark", null]
</syntaxhighlight>
===Java===
<
public interface Animal {
void makeSound()
}
Line 363 ⟶ 376:
public class NullAnimal implements Animal {
public void makeSound() {
}
}
</syntaxhighlight>
This code illustrates a variation of the C++ example, above, using the Java language. As with C++, a null class can be instantiated in situations where a reference to an <code>Animal</code> object is required, but there is no appropriate object available. A null <code>Animal</code> object is possible (<code>Animal myAnimal = null;</code>) and could be useful as a place-holder, but may not be used for calling a method. In this example, <code>myAnimal.makeSound();</code> will throw a NullPointerException. Therefore, additional code may be necessary to test for null objects.
Line 373 ⟶ 386:
=== PHP ===
<
interface Animal
{ public function makeSound();
}
class Dog implements Animal
{ public function makeSound()
{
echo "Woof...\n"; }
}
class Cat implements Animal
{ public function makeSound()
{
echo "Meowww...\n"; }
}
class NullAnimal implements Animal
{ public function makeSound()
// silence...
}
Line 397 ⟶ 417:
$animalType = 'elephant';
switch($animalType) {▼
function makeAnimalFromAnimalType(string $animalType): Animal
▲{
$animal = new Dog();▼
▲ switch ($animalType) {
case '
return new Cat();
▲ }
}
function animalMakeSound(Animal $animal): void
▲{
}
foreach ([
makeAnimalFromAnimalType('dog'),
makeAnimalFromAnimalType('NullAnimal'),
makeAnimalFromAnimalType('cat'),
] as $animal) {
// That's also reduce null handling code
animalMakeSound($animal);
}
</syntaxhighlight>
▲$animal->makeSound(); // ..the null animal makes no sound
=== Visual Basic .NET ===
The following null object pattern implementation demonstrates the concrete class providing its corresponding null object in a static field <code>Empty</code>. This approach is frequently used in the .NET Framework (<code>String.Empty</code>, <code>EventArgs.Empty</code>, <code>Guid.Empty</code>, etc.).
<
Public Class Animal
Public Shared ReadOnly Empty As Animal = New AnimalEmpty()
Line 430 ⟶ 466:
End Sub
End Class
</syntaxhighlight>
==Criticism==
This pattern should be used carefully, as it can make errors/bugs appear as normal program execution.<ref>Fowler, Martin (1999). Refactoring,
Care should be taken not to implement this pattern just to avoid null checks and make code more readable, since the harder
==See also==
Line 445 ⟶ 481:
==External links==
*[http://www.cs.oberlin.edu/~jwalker/nullObjPattern/
*[http://martinfowler.com/eaaCatalog/specialCase.html Martin Fowler's description of Special Case, a slightly more general pattern]
*[http://www.owlnet.rice.edu/~comp212/00-spring/handouts/week06/null_object_revisited.htm Null Object Pattern Revisited]
|