In older Lisp dialects that didn't have anything like Common Lisp's condition system, CATCH
and THROW
were used for error handling. However, to keep them manageable, the catch tags were usually just quoted symbols, so you CATCH
and a THROW
whether they would hook up at runtime. In Common Lisp you'll rarely have any call to use CATCH
and THROW
since the condition system is so much more flexible.
The last special operator related to controlling the stack is another one I've mentioned in passing before— UNWIND-PROTECT
. UNWIND-PROTECT
lets you control what happens as the stack unwinds—to make sure that certain code always runs regardless of how control leaves the scope of the UNWIND-PROTECT
, whether by a normal return, by a restart being invoked, or by any of the ways discussed in this section.[214] The basic skeleton of UNWIND-PROTECT
looks like this:
(unwind-protect
The single UNWIND-PROTECT
after the cleanup forms run. The cleanup forms are evaluated in the same dynamic environment as the UNWIND-PROTECT
, so the same dynamic variable bindings, restarts, and condition handlers will be visible to code in cleanup forms as were visible just before the UNWIND-PROTECT
.
You'll occasionally use UNWIND-PROTECT
directly. More often you'll use it as the basis for WITH-
style macros, similar to WITH-OPEN- FILE
, that evaluate any number of body forms in a context where they have access to some resource that needs to be cleaned up after they're done, regardless of whether they return normally or bail via a restart or other nonlocal exit. For example, if you were writing a database library that defined functions open-connection
and close-connection
, you might write a macro like this:[215]
(defmacro with-database-connection ((var &rest open-args) &body body)
`(let ((,var (open-connection ,@open-args)))
(unwind-protect (progn ,@body)
(close-connection ,var))))
which lets you write code like this:
(with-database-connection (conn :host 'foo' :user 'scott' :password 'tiger')
(do-stuff conn)
(do-more-stuff conn))
and not have to worry about closing the database connection, since the UNWIND- PROTECT
will make sure it gets closed no matter what happens in the body of the with-database-connection
form.
Another feature of Common Lisp that I've mentioned in passing—in Chapter 11, when I discussed GETHASH
—is the ability for a single form to return multiple values. I'll discuss it in greater detail now. It is, however, slightly misplaced in a chapter on special operators since the ability to return multiple values isn't provided by just one or two special operators but is deeply integrated into the language. The operators you'll most often use when dealing with multiple values are macros and functions, not special operators. But it is the case that the basic ability to get at multiple return values is provided by a special operator, MULTIPLE-VALUE-CALL
, upon which the more commonly used MULTIPLE-VALUE-BIND
macro is built.
The key thing to understand about multiple values is that returning multiple values is quite different from returning a list—if a form returns multiple values, unless you do something specific to capture the multiple values, all but the GETHASH
, which returns two values: the value found in the hash table and a boolean that's NIL
when no value was found. If it returned those two values in a list, every time you called GETHASH
you'd have to take apart the list to get at the actual value, regardless of whether you cared about the second return value. Suppose you have a hash table, *h*
, that contains numeric values. If GETHASH
returned a list, you couldn't write something like this:
(+ (gethash 'a *h*) (gethash 'b *h*))
because +
expects its arguments to be numbers, not lists. But because the multiple value mechanism silently discards the secondary return value when it's not wanted, this form works fine.
There are two aspects to using multiple values—returning multiple values and getting at the nonprimary values returned by forms that return multiple values. The starting points for returning multiple values are the functions VALUES
and VALUES-LIST
. These are regular functions, not special operators, so their arguments are passed in the normal way. VALUES
takes a variable number of arguments and returns them as multiple values; VALUES-LIST
takes a single list and returns its elements as multiple values. In other words:
(values-list x) === (apply #'values x)
The mechanism by which multiple values are returned is implementation dependent just like the mechanism for passing arguments into functions is. Almost all language constructs that return the value of some subform will 'pass through' multiple values, returning all the values returned by the subform. Thus, a function that returns the result of calling VALUES
or VALUES-LIST
will itself return multiple values—and so will another function whose result comes from calling the first function. And so on.[216]
But when a form is evaluated in a value position, only the primary value will be used, which is why the previous addition form works the way you'd expect. The special operator MULTIPLE-VALUE- CALL
provides the mechanism for getting your hands on the multiple values returned by a form. MULTIPLE-VALUE-CALL
is similar to FUNCALL
except that while FUNCALL
is a regular function and, therefore, can see and pass on only the primary values passed to it, MULTIPLE-VALUE-CALL
passes, to the function returned by its first subform,
(funcall #'+ (values 1 2) (values 3 4)) ==> 4
(multiple-value-call #'+ (values 1 2) (values 3 4)) ==> 10
However, it's fairly rare that you'll simply want to pass all the values returned by a function onto another function. More likely, you'll want to stash the multiple values in different variables and then do something with them. The MULTIPLE-VALUE-BIND
macro, which you saw in Chapter 11, is the most frequently used operator for accepting multiple return values. Its skeleton looks like this:
(multiple-value-bind (
The