Unwinding the Stack
Another aspect of the language that special operators give you control over is the behavior of the call stack. For instance, while you normally use **BLOCK**
and **TAGBODY**
to manage the flow of control within a single function, you can also use them, in conjunction with closures, to force an immediate nonlocal return from a function further down on the stack. That’s because **BLOCK**
names and **TAGBODY**
tags can be closed over by any code within the lexical scope of the **BLOCK**
or **TAGBODY**
. For example, consider this function:
(defun foo ()
(format t "Entering foo~%")
(block a
(format t " Entering BLOCK~%")
(bar #'(lambda () (return-from a)))
(format t " Leaving BLOCK~%"))
(format t "Leaving foo~%"))
The anonymous function passed to bar
uses **RETURN-FROM**
to return from the **BLOCK**
. But that **RETURN-FROM**
doesn’t get evaluated until the anonymous function is invoked with **FUNCALL**
or **APPLY**
. Now suppose bar
looks like this:
(defun bar (fn)
(format t " Entering bar~%")
(baz fn)
(format t " Leaving bar~%"))
Still, the anonymous function isn’t invoked. Now look at baz
.
(defun baz (fn)
(format t " Entering baz~%")
(funcall fn)
(format t " Leaving baz~%"))
Finally the function is invoked. But what does it mean to **RETURN-FROM**
a block that’s several layers up on the call stack? Turns out it works fine—the stack is unwound back to the frame where the **BLOCK**
was established and control returns from the **BLOCK**
. The **FORMAT**
expressions in foo
, bar
, and baz
show this:
CL-USER> (foo)
Entering foo
Entering BLOCK
Entering bar
Entering baz
Leaving foo
NIL
Note that the only “Leaving . . .” message that prints is the one that appears after the **BLOCK**
in foo
.
Because the names of blocks are lexically scoped, a **RETURN-FROM**
always returns from the smallest enclosing **BLOCK**
in the lexical environment where the **RETURN-FROM**
form appears even if the **RETURN-FROM**
is executed in a different dynamic context. For instance, bar
could also contain a **BLOCK**
named a
, like this:
(defun bar (fn)
(format t " Entering bar~%")
(block a (baz fn))
(format t " Leaving bar~%"))
This extra **BLOCK**
won’t change the behavior of foo
at all—the name a
is resolved lexically, at compile time, not dynamically, so the intervening block has no effect on the **RETURN-FROM**
. Conversely, the name of a **BLOCK**
can be used only by **RETURN-FROM**
s appearing within the lexical scope of the **BLOCK**
; there’s no way for code outside the block to return from the block except by invoking a closure that closes over a **RETURN-FROM**
from the lexical scope of the **BLOCK**
.
**TAGBODY**
and **GO**
work the same way, in this regard, as **BLOCK**
and **RETURN-FROM**
. When you invoke a closure that contains a **GO**
form, if the **GO**
is evaluated, the stack will unwind back to the appropriate **TAGBODY**
and then jump to the specified tag.
**BLOCK**
names and **TAGBODY**
tags, however, differ from lexical variable bindings in one important way. As I discussed in Chapter 6, lexical bindings have indefinite extent, meaning the bindings can stick around even after the binding form has returned. **BLOCK**
s and **TAGBODY**
s, on the other hand, have dynamic extent—you can **RETURN-FROM**
a **BLOCK**
or **GO**
to a **TAGBODY**
tag only while the **BLOCK**
or **TAGBODY**
is on the call stack. In other words, a closure that captures a block name or **TAGBODY**
tag can be passed down the stack to be invoked later, but it can’t be returned up the stack. If you invoke a closure that tries to **RETURN-FROM**
a **BLOCK**
, after the **BLOCK**
itself has returned, you’ll get an error. Likewise, trying to **GO**
to a **TAGBODY**
that no longer exists will cause an error.7
It’s unlikely you’ll need to use **BLOCK**
and **TAGBODY**
yourself for this kind of stack unwinding. But you’ll likely be using them indirectly whenever you use the condition system, so understanding how they work should help you understand better what exactly, for instance, invoking a restart is doing.8
**CATCH**
and **THROW**
are another pair of special operators that can force the stack to unwind. You’ll use these operators even less often than the others mentioned so far—they’re holdovers from earlier Lisp dialects that didn’t have Common Lisp’s condition system. They definitely shouldn’t be confused with try
/catch
and try
/except
constructs from languages such as Java and Python.
**CATCH**
and **THROW**
are the dynamic counterparts of **BLOCK**
and **RETURN-FROM**
. That is, you wrap **CATCH**
around a body of code and then use **THROW**
to cause the **CATCH**
form to return immediately with a specified value. The difference is that the association between a **CATCH**
and **THROW**
is established dynamically—instead of a lexically scoped name, the label for a **CATCH**
is an object, called a catch tag, and any **THROW**
evaluated within the dynamic extent of the **CATCH**
that throws that object will unwind the stack back to the **CATCH**
form and cause it to return immediately. Thus, you can write a version of the foo
, bar
, and baz
functions from before using **CATCH**
and **THROW**
instead of **BLOCK**
and **RETURN-FROM**
like this:
(defparameter *obj* (cons nil nil)) ; i.e. some arbitrary object
(defun foo ()
(format t "Entering foo~%")
(catch *obj*
(format t " Entering CATCH~%")
(bar)
(format t " Leaving CATCH~%"))
(format t "Leaving foo~%"))
(defun bar ()
(format t " Entering bar~%")
(baz)
(format t " Leaving bar~%"))
(defun baz ()
(format t " Entering baz~%")
(throw *obj* nil)
(format t " Leaving baz~%"))
Notice how it isn’t necessary to pass a closure down the stack—baz
can call **THROW**
directly. The result is quite similar to the earlier version.
CL-USER> (foo)
Entering foo
Entering CATCH
Entering bar
Entering baz
Leaving foo
NIL
However, **CATCH**
and **THROW**
are almost too dynamic. In both the **CATCH**
and the **THROW**
, the tag form is evaluated, which means their values are both determined at runtime. Thus, if some code in bar
reassigned or rebound *obj*
, the **THROW**
in baz
wouldn’t throw to the same **CATCH**
. This makes **CATCH**
and **THROW**
much harder to reason about than **BLOCK**
and **RETURN-FROM**
. The only advantage, which the version of foo
, bar
, and baz
that use **CATCH**
and **THROW**
demonstrates, is there’s no need to pass down a closure in order for low-level code to return from a **CATCH**
--any code that runs within the dynamic extent of a **CATCH**
can cause it to return by throwing the right object.
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 could tell by looking at a **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.9 The basic skeleton of **UNWIND-PROTECT**
looks like this:
(unwind-protect protected-form
cleanup-form*)
The single protected-form is evaluated, and then, regardless of how it returns, the cleanup-forms are evaluated. If the protected-form returns normally, then whatever it returns is returned from the **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:10
(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.