Tag Archives: lisp

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

The less-familiar parts of Lisp for beginners — shared-initialize

We’ll now describe, briefly, the standard generic function shared-initialize.  The way this function is interesting to the programmer is very much like that of initialize-instance, so the reader might want to review that earlier article.  In that article, I discussed how initialize-instance is called within make-instance, and by specializing an :after method on initialize-instance, it is possible to write additional code similar to what a C++ programmer would think of as the body of a constructor.  Where initialize-instance fills in the slots, like the initialization list in a constructor, the :after method on it allows the programmer to do other things than just fill in member slots.

Since that article appeared, though, we’ve talked about other ways that an object can be made.  We saw reinitialize-instance, and make-instances-obsolete, the latter as a prelude to update-instance-for-redefined-class, which we have not yet discussed.  These two cases, which do not correspond to any obvious C++ equivalent, do not call initialize-instance, so the programmer’s :after method won’t be called if they are used.

This is where shared-initialize enters the picture.  The shared-initialize generic function is called by initialize-instance, and also by reinitialize-instance, update-instance-for-redefined-class, and update-instance-for-different-class.  That means that by specializing an :after method on shared-initialize, just the way we did it earlier for initialize-instance, we can write code that will be executed whenever the new object is created by any of these routes.  Naturally, if the code should do different things for these different cases, you’ll want to specialize on the outer methods, but if they all have to run the same code, shared-initialize covers all the cases at once.

The less-familiar parts of Lisp for beginners — shadowing-import

Now, we discuss shadowing-import.  We skipped over import earlier, as it seemed fairly simple, but shadowing-import is interesting in the way it differs from import, so we’ll talk about it a bit now.

The import function allows a symbol from one package to be visible in another.  Note, however, that if a symbol by that name already exists in the package into which the symbol is being imported, an error condition is raised.  To avoid the error, you first have to unintern the existing symbol in the package before importing the symbol from the other package.

The shadowing-import function works like import, but shadows any existing symbol rather than raising an error condition.  The imported symbol replaces the formerly-existing one.

Here is a transcript of that behaviour.  Note that import fails with an error, while shadowing-import succeeds:
*slime-repl sbcl*

CL-USER> (make-package 'foreign)
#<PACKAGE "FOREIGN">
CL-USER> (intern "MY-SYMBOL" 'foreign)
FOREIGN::MY-SYMBOL
NIL
CL-USER> (intern "MY-SYMBOL")
MY-SYMBOL
NIL
CL-USER> (import 'foreign::MY-SYMBOL)
; Evaluation aborted on #<NAME-CONFLICT {1002FD4373}>.
CL-USER> (shadowing-import 'foreign::MY-SYMBOL)
T

The less familiar parts of Lisp for beginners — summary R

I’ve written a few posts about features of the Lisp language that a newcomer arriving from C++ might not have encountered.  I’m going through them alphabetically, so here is a summary page of the functions beginning with the letter R:

random

read-preserving-whitespace

read-delimited-list

read-from-string

read-line

readtable-case

reduce

reinitialize-instance

remove-method

remprop

restart-bind

restart-case

rotatef

row-major-aref