catch and throw
One way to use catch and throw is to exit from a doubly
nested loop. (In most languages, this would be done with a "go to".)
Here we compute (foo i j) for i and j
varying from 0 to 9:
(defun search-foo ()
(catch 'loop
(let ((i 0))
(while (< i 10)
(let ((j 0))
(while (< j 10)
(if (foo i j)
(throw 'loop (list i j)))
(setq j (1+ j))))
(setq i (1+ i))))))
If foo ever returns non-nil, we stop immediately and return a
list of i and j. If foo always returns nil, the
catch returns normally, and the value is nil, since that
is the result of the while.
Here are two tricky examples, slightly different, showing two
return points at once. First, two return points with the same tag,
hack:
(defun catch2 (tag)
(catch tag
(throw 'hack 'yes)))
=> catch2
(catch 'hack
(print (catch2 'hack))
'no)
-| yes
=> no
Since both return points have tags that match the throw, it goes to
the inner one, the one established in catch2. Therefore,
catch2 returns normally with value yes, and this value is
printed. Finally the second body form in the outer catch, which is
'no, is evaluated and returned from the outer catch.
Now let's change the argument given to catch2:
(defun catch2 (tag)
(catch tag
(throw 'hack 'yes)))
=> catch2
(catch 'hack
(print (catch2 'quux))
'no)
=> yes
We still have two return points, but this time only the outer one has
the tag hack; the inner one has the tag quux instead.
Therefore, throw makes the outer catch return the value
yes. The function print is never called, and the
body-form 'no is never evaluated.
Go to the first, previous, next, last section, table of contents.