Next: unwind syntaxes, Up: unwind [Contents][Index]
The syntax with-unwind-handler implements the core mechanism. unwind-protect
offers a syntax similar to the one of the Common Lisp macro with the same name. The former is meant
to be used as follows:
(let ((port (open-output-file "file.ext")))
(with-unwind-handler
(lambda (why)
(close-output-port port))
(lambda ()
(put-bytevector port '#ve(ascii "ciao")))))
and the latter as follows:
(let ((port (open-output-file "file.ext")))
(unwind-protect
(put-bytevector port '#ve(ascii "ciao"))
(close-output-port port)))
first we allocate a resource (in this case the port); then we use it in the body forms; finally we release it in the clean–up forms.
When using the mechanism:
dynamic-wind calls. These would be nasty errors, because the dynamic
environment would get corrupted and recovering correctly might be impossible; so we must
really write and debug such in–guard and out–guard thunks with care.
(with-exception-handler
(lambda (E)
(with-blocked-exceptions
(lambda ()
(handle E))))
(lambda ()
(do-something-useful)))
but it is not very satisfying. Another possibility is:
(define-condition-type &originally-raised
&condition
make-originally-raised-condition
originally-raised-condition?
(object originally-raised-object))
(with-exception-handler
(lambda (E)
(with-exception-handler
(lambda (X)
(raise-continuable
(condition X
(make-originally-raised-condition E))))
(lambda ()
(handle E))))
(lambda ()
(do-something-useful)))
If the bodacious answer to both the decisions is “We trust”: we can nest at will uses of
with-unwind-handler:
(define (outer)
(with-unwind-handler
(lambda (why)
(outer-unwind-handler))
(lambda ()
(do-something-useful)
(inner))))
(define (inner)
(with-unwind-handler
(lambda (why)
(inner-unwind-handler))
(lambda ()
(do-some-other-useful-thing))))
(outer)
beware: unwind handlers are evaluated in the dynamic environment of the use of
with-unwind-handler.
Otherwise, we must avoid error handlers to cause the execution flow to cross an unwind protection
boundary; we can do it by using compensations and the standard guard syntax:
(define (outer)
(push-compensation-thunk
(lambda ()
(outer-unwind-handler)))
(do-something-useful)
(inner))
(define (inner)
(push-compensation-thunk
(lambda ()
(inner-unwind-handler)))
(do-some-other-useful-thing))
(with-compensations
(with-blocked-exceptions
(lambda ()
(guard (E ((type-one-error? E)
(handle E))
(else
(do-something-dammit!!!)))
(outer)))))
or by using the compensations and the try syntax defined by MMCK Exceptional Conditions:
(define (outer)
(push-compensation-thunk
(lambda ()
(outer-unwind-handler)))
(do-something-useful)
(inner))
(define (inner)
(push-compensation-thunk
(lambda ()
(inner-unwind-handler)))
(do-some-other-useful-thing))
(with-compensations
(with-blocked-exceptions
(lambda ()
(try
(outer)
(catch E
((&type-one)
(handle E))
(else
(do-something-dammit!!!)))))))
beware: compensation handlers are evaluated in the dynamic environment of the use of
with-compensations.
Next: unwind syntaxes, Up: unwind [Contents][Index]
This document describes version 0.1.0-devel.1 of MMCK Exceptional Conditions.