Warning: This is the manual of the legacy Guile 2.0 series. You may want to read the manual of the current stable series instead.
Next: Throw, Previous: Catch, Up: Exceptions [Contents][Index]
It’s sometimes useful to be able to intercept an exception that is being
thrown before the stack is unwound. This could be to clean up some
related state, to print a backtrace, or to pass information about the
exception to a debugger, for example. The with-throw-handler
procedure provides a way to do this.
Add handler to the dynamic context as a throw handler for key key, then invoke thunk.
This behaves exactly like catch
, except that it does not unwind
the stack before invoking handler. If the handler procedure
returns normally, Guile rethrows the same exception again to the next
innermost catch or throw handler. handler may exit nonlocally, of
course, via an explicit throw or via invoking a continuation.
Typically handler is used to display a backtrace of the stack at
the point where the corresponding throw
occurred, or to save off
this information for possible display later.
Not unwinding the stack means that throwing an exception that is handled
via a throw handler is equivalent to calling the throw handler handler
inline instead of each throw
, and then omitting the surrounding
with-throw-handler
. In other words,
(with-throw-handler 'key (lambda () … (throw 'key args …) …) handler)
is mostly equivalent to
((lambda () … (handler 'key args …) …))
In particular, the dynamic context when handler is invoked is that
of the site where throw
is called. The examples are not quite
equivalent, because the body of a with-throw-handler
is not in
tail position with respect to the with-throw-handler
, and if
handler exits normally, Guile arranges to rethrow the error, but
hopefully the intention is clear. (For an introduction to what is meant
by dynamic context, See Dynamic Wind.)
The above scm_with_throw_handler
takes Scheme procedures as body
(thunk) and handler arguments. scm_c_with_throw_handler
is an
equivalent taking C functions. See scm_c_catch
(see Catch)
for a description of the parameters, the behaviour however of course
follows with-throw-handler
.
If thunk throws an exception, Guile handles that exception by
invoking the innermost catch
or throw handler whose key matches
that of the exception. When the innermost thing is a throw handler,
Guile calls the specified handler procedure using (apply
handler key args)
. The handler procedure may either return
normally or exit non-locally. If it returns normally, Guile passes the
exception on to the next innermost catch
or throw handler. If it
exits non-locally, that exit determines the continuation.
The behaviour of a throw handler is very similar to that of a
catch
expression’s optional pre-unwind handler. In particular, a
throw handler’s handler procedure is invoked in the exact dynamic
context of the throw
expression, just as a pre-unwind handler is.
with-throw-handler
may be seen as a half-catch
: it does
everything that a catch
would do until the point where
catch
would start unwinding the stack and dynamic context, but
then it rethrows to the next innermost catch
or throw handler
instead.
Note also that since the dynamic context is not unwound, if a
with-throw-handler
handler throws to a key that does not match
the with-throw-handler
expression’s key, the new throw may
be handled by a catch
or throw handler that is closer to
the throw than the first with-throw-handler
.
Here is an example to illustrate this behavior:
(catch 'a (lambda () (with-throw-handler 'b (lambda () (catch 'a (lambda () (throw 'b)) inner-handler)) (lambda (key . args) (throw 'a)))) outer-handler)
This code will call inner-handler
and then continue with the
continuation of the inner catch
.
Next: Throw, Previous: Catch, Up: Exceptions [Contents][Index]