(guile.info.gz) Lazy Catch
Info Catalog
(guile.info.gz) Throw
(guile.info.gz) Exceptions
(guile.info.gz) Exception Implementation
26.7.4 Catch Without Unwinding
------------------------------
A "lazy catch" is used in the same way as a normal `catch', with KEY,
THUNK and HANDLER arguments specifying the exception type, normal case
code and handler procedure, but differs in one important respect: the
handler procedure is executed without unwinding the call stack from the
context of the `throw' expression that caused the handler to be invoked.
-- Scheme Procedure: lazy-catch key thunk handler
-- C Function: scm_lazy_catch (key, thunk, handler)
This behaves exactly like `catch', except that it does not unwind
the stack before invoking HANDLER. The HANDLER procedure is not
allowed to return: it must throw to another catch, or otherwise
exit non-locally.
Typically, HANDLER should save any desired state associated with the
stack at the point where the corresponding `throw' occurred, and then
throw an exception itself -- usually the same exception as the one it
caught. If HANDLER is invoked and does _not_ throw an exception, Guile
itself throws an exception with key `misc-error'.
Not unwinding the stack means that throwing an exception that is
caught by a `lazy-catch' is _almost_ equivalent to calling the
`lazy-catch''s handler inline instead of each `throw', and then
omitting the surrounding `lazy-catch'. In other words,
(lazy-catch 'key
(lambda () ... (throw 'key args ...) ...)
handler)
is _almost_ equivalent to
((lambda () ... (handler 'key args ...) ...))
But why only _almost_? The difference is that with `lazy-catch' (as
with normal `catch'), the dynamic context is unwound back to just
outside the `lazy-catch' expression before invoking the handler. (For
an introduction to what is meant by dynamic context, Dynamic
Wind.)
Then, when the handler _itself_ throws an exception, that exception
must be caught by some kind of `catch' (including perhaps another
`lazy-catch') higher up the call stack.
The dynamic context also includes `with-fluids' blocks (REFFIXME),
so the effect of unwinding the dynamic context can also be seen in fluid
variable values. This is illustrated by the following code, in which
the normal case thunk uses `with-fluids' to temporarily change the
value of a fluid:
(define f (make-fluid))
(fluid-set! f "top level value")
(define (handler . args)
(cons (fluid-ref f) args))
(lazy-catch 'foo
(lambda ()
(with-fluids ((f "local value"))
(throw 'foo)))
handler)
=>
("top level value" foo)
((lambda ()
(with-fluids ((f "local value"))
(handler 'foo))))
=>
("local value" foo)
In the `lazy-catch' version, the unwinding of dynamic context restores
`f' to its value outside the `with-fluids' block before the handler is
invoked, so the handler's `(fluid-ref f)' returns the external value.
`lazy-catch' is useful because it permits the implementation of
debuggers and other reflective programming tools that need to access the
state of the call stack at the exact point where an exception or an
error is thrown. For an example of this, see REFFIXME:stack-catch.
Info Catalog
(guile.info.gz) Throw
(guile.info.gz) Exceptions
(guile.info.gz) Exception Implementation
automatically generated byinfo2html