Null object: Difference between revisions

→‎{{header|Common Lisp}}: Rewrite. Also, no discussion of unbound variables since the task description explicitly says it's not about this issue.
(Move BASIC and part of ActionScript to Undefined values.)
(→‎{{header|Common Lisp}}: Rewrite. Also, no discussion of unbound variables since the task description explicitly says it's not about this issue.)
Line 169:
 
=={{header|Common Lisp}}==
<code>nil</code> is in fact the ''only'' false value. So a regular Boolean test will suffice to determine whether an object is <code>nil</code>.
 
====Basics====
<lang lisp>(format t "The object is~A nil"
(if some-object " not" ""))</lang>
 
ThereCommon isLisp has an object denoted alsoby the functionsymbol <code>nullnil</code>. whichWhen teststhe whether some value issymbol <code>nil</code>; it is equivalentevaluated toas <code>not</code>an butexpression, forit theevaluates intentto conveyeditself.
 
<code>nil</code> uniquely represents boolean false, and so code like <lang lisp>(if (condition) (do-this))</lang> is actually testing whether <code>(condition)</code> returns the value <code>nil</code>. The object <code>nil</code> is also used to denote the empty list which also terminates other lists. The value is also used as a default when some function returns fewer values than expected. <code>(list (values))</code> produces <code>(nil)</code> (list containing one element, which is the empty list), because <code>(values)</code> produces no value, but the function call <code>(list ...)</code> needs to reduce the expression to a single argument value, and so <code>nil</code> is supplied.
On the other hand, a symbol bound to <code>nil</code> is distinct from a symbol without any bindings. Trying to read the value of unbound symbol is an error of type <code>unbound-variable</code>. You can test whether a symbol is globally bound with <code>boundp</code>.
 
====Beginnings of Null Object====
<lang lisp>(format t "The symbol is~A bound"
 
(if (boundp 'some-object) "" " not"))</lang>
The idea of making functions accept <code>nil</code> without failing did not appear in early Lisps. For instance <code>(car nil)</code> was erroneous: it was incorrect to try to access the first element of a non-list.
 
The defaulting behavior <code>(car nil)</code> which Common Lisp programmers take for granted was introduced in InterLisp, and then copied into MacLisp. (InterLisp had other liberties that do not survive in Common Lisp: it was possible to call a function with insufficient arguments, and the missing ones defaulted to <code>nil</code>. Likewise, excess arguments were ignored. CL has a disciplined syntax and semantics for default and variale arguments.)
 
This <code>(car nil) -> nil</code> behavior shows <code>nil</code> in an kind of new role: the role of a null object which takes methods that apply to other objects and provides some default non-failing behavior. It is the beginnings of the "null object design pattern".
 
====Object-Oriented Null Object====
 
In Common Lisp, in fact, there is a class called <code>null</code>, of which the object <code>nil</code> is understood to be the only instance. Furthermore, the <code>null</code> class is at the bottom of the type spindle: it is a subclass of every class. This is in contrast with the type <code>T</code> which is a superclass of every class.
 
Since <code>null</code> is at the bottom of the class hierarchy, it is possible to write methods specialized to parameters of class <code>null</code> which will only be applicable if the argument is the object <code>nil</code>. No other object is a subtype of <code>null</code>.
 
Some traditional Lisp functions could be expressed using the object system like this.
Suppose that the <code>car</code> function did not have a safe defaulting behavior for <code>nil</code>. We could use the methods of the object system to define a <code>car*</code> which does have the safe behavior:
 
<lang lisp>(defmethod car* ((arg cons))
(car arg))
 
(defmethod car* ((arg null))
nil)</lang>
 
Now if we invoke <code>car*</code> on something which is neither a cons, nor <code>nil</code>, we get an error about no applicable method being found.
 
We can handle that ourselves by writing a method specialized to the master supertype <code>t</code>:
 
<lang lisp>(defmethod car* ((arg t)) ;; can just be written (defmethod car* (arg) ...)
(error "CAR*: ~s is neither a cons nor nil" arg))</lang>
 
The classes <code>t</code> and <code>null</code> are widely exploited in Lisp OO programming.
 
=={{header|D}}==
Anonymous user