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.