Next: iklib unwind-protect syntaxes, Up: iklib unwind-protect [Index]
The syntax with-unwind-handler
implements the core mechanism;
with-unwind-protection
is an alias for it.
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:
#!vicare (import (vicare)) (let ((port (open-file-output-port "file.ext"))) (with-unwind-handler (lambda (why) (close-output-port port)) (lambda () (put-bytevector port '#ve(ascii "ciao")))))
and the latter as follows:
#!vicare (import (vicare)) (let ((port (open-file-output-port "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-protection
:
(define (outer) (with-unwind-protection (lambda (why) (outer-unwind-handler)) (lambda () (do-something-useful) (inner)))) (define (inner) (with-unwind-protection (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-protection
.
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
Vicare:
(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: iklib unwind-protect syntaxes, Up: iklib unwind-protect [Index]