Category Archives: Uncategorized

The less-familiar parts of Lisp for beginners — slot-makunbound

Earlier, we discussed slot-boundp.  A named slot in an instance will not be bound to a value until it has been assigned by one of several means.  An unbound slot does not have a nil value, it has no value at all, and it is an error to attempt to read its contents.

Under some circumstances, the programmer may want to take a slot that has an associated value, and return it to that pristine, unbound state.  This is what slot-makunbound does.  If the slot has a bound value, that value is discarded and the slot is returned to the unbound state.

The less-familiar parts of Lisp for beginners — slot-exists-p

In our last article, we talked about slots in classes.  I mentioned there that slot-boundp could not tell you whether a particular named slot was present in a class, it raises an error if you ask that function to act on a non-existent slot name.

So, how do you find out whether a particular object has a slot of a given name?  That’s where slot-exists-p comes in.  It returns non-nil if the named slot exists in the instance, either directly or through inheritance.

Why would a programmer want to do this?  When does the programmer not know the names of the slots in a particular class, and should he or she really be messing with a class about which they know so very little?  Well, if the coding specification for a project is sufficiently detailed, one might, for instance, say that programmer-defined classes are permitted, but not required, to define a slot called “time-last-modified”, and if that slot is defined, the code takes action to keep that slot updated.  I’ve seen it used in similar contexts, but rarely.

The less-familiar parts of Lisp for beginners — slot-boundp

Over the next few articles, we’ll be discussing functions related to slots in an instance.  When a class is defined, its definition establishes the slots associated with that class, either directly or through inheritance.  Shared slots (static members, in the language of C++) are created immediately upon definition, but local slots (non-static members in C++) are not manifested before instances of the object are created.  A local slot within a particular instance can be bound or unbound.  It is bound by assigning a value to it, either by :initform, :initarg, or direct assignment through accessors or the application of setf acting on the slot-value function.  If none of those actions has taken place on a local slot in a particular instance, the local slot will be unbound.  Note that assigning nil to a slot still makes it bound.

We start with slot-boundp.  This function allows the programmer to determine whether or not a particular named slot in an instance has been bound.  The most likely place to use this is in an :after method specialized on the class for the initialize-instance generic function.  The programmer can use it to determine whether the slot was initialized, perhaps via an :initarg invocation, and take appropriate action to fill in the variable if no such value was assigned.

Here is a short transcript showing the use of slot-boundp:
*slime-repl sbcl*

CL-USER> (defclass test-class ()
           ((slot-1             :accessor get-1 
                                :initform nil)
            (slot-2             :accessor get-2)))
#<STANDARD-CLASS TEST-CLASS>
CL-USER> (slot-boundp (make-instance 'test-class) 'slot-1)
T
CL-USER> (slot-boundp (make-instance 'test-class) 'slot-2)
NIL
CL-USER> (slot-boundp (make-instance 'test-class) 'slot-3)
; Evaluation aborted on #<SIMPLE-ERROR "~@<When attempting to ~A, the slot ~S is missing from the ~
          object ~S.~@:>" {100338F633}>.

Note that if I call slot-boundp on a slot name that is not defined in the class, an error is signaled.  This function does not enable the programmer to determine whether a particular slot name is in the definition of the class, merely whether a certain slot, known to be in the definition, is bound to a value in a particular instance of this class.

The less-familiar parts of Lisp for beginners — signal

Our review of obscure Lisp features for newcomers arriving from C++ now comes to signal.  Some time ago I wrote a series of articles about exception handling in Lisp from a C++ perspective, you might want to review that series here.

As discussed in the earlier series, signal behaves somewhat like a C++ throw, but with some important differences.  Foremost among them is that if there is no handler for the signaled condition, the signal form returns nil and execution continues at the next statement.  This is unlike C++, where an unhandled exception causes an immediate ABEND.

The less-familiar parts of Lisp for beginners — shiftf

Continuing through obscure Lisp commands, we arrive at the shiftf macro.  This is very similar to the rotatef macro that we described earlier.  The difference is that the first place, rather than rotating to the last place as in rotatef, is removed and a new programmer-supplied value is inserted into the last place.  The dropped value is returned.  Here are some examples:
*slime-repl sbcl*

CL-USER> (let ((one 1)
               (two 2)
               (three 3))
           (rotatef one two three)
           (format t
                   "After rotatef, one= ~D  two= ~D  three= ~D~%"
                   one two three))
After rotatef, one= 2  two= 3  three= 1
NIL
CL-USER> (let ((one 1)
               (two 2)
               (three 3))
           (shiftf one two three 10)
           (format t
                   "After shiftf, one= ~D  two= ~D  three= ~D~%"
                   one two three))
After shiftf, one= 2  two= 3  three= 10
NIL
CL-USER> (let ((mylist (list 1 2 3 4 5)))
           (rotatef (first mylist)
                    (second mylist)
                    (third mylist))
           (format t "After rotatef, mylist= ~A~%" mylist))
After rotatef, mylist= (2 3 1 4 5)
NIL
CL-USER> (let ((mylist (list 1 2 3 4 5)))
           (shiftf (first mylist)
                   (second mylist)
                   (third mylist)
                   10)
           (format t "After shiftf, mylist= ~A~%" mylist))
After shiftf, mylist= (2 3 10 4 5)
NIL