1. Common Lisp's unwind-protect allows multiple cleanup forms. Personally I don't see much benefit of allowing it, but to avoid confusions, we may adopt the same API.
2. This is more involved. The cleanup forms of unwind-protect are literally for cleaning up, e.g. releasing resources. This poses an issue in Scheme; with continuations, control can reenter protected-form. Executing cleanup-forms in the after thunk of dynamic-wind invalides such applications as coroutines. I don't think there's a clear solution, for there's no way to know for sure if the control transfer out of protected-form is final. In Gauche, we transfer (unwind-protect protected-form cleanup-forms ...) to roughly this code: ==== (let ((done #f)) (define (cleanup) (unless done (set! done #t) cleanup-form ...)) (guard (e ((condition-has-type? e <serious-condition>) (cleanup) (raise e)) (else (raise e))) (receive r protected-form (cleanup) (apply values r)))) ==== This code relies on some Gauche-specific behaviors. (Actual code is a lot more messy for it accesses Gauche runtime internals) - Gauche's exception system predates srfi-34 etc, and our <serious-condition> isn't allowed to be continuable. We only call cleanup forms when a serious condition is thrown (or protected form exits normally). - If controls goes out with other type of conditions, cleanup forms aren't executed, for the condition may be continuable. It's up to the user to deal with the consequences. If the cleanup forms are so important, translate conditions to serious ones in protected forms. - Control transfers other than raise/error don't trigger cleanup forms. It's up to the user to ensure such control should return to the protected-form eventually. - If a continuation is captured in protected-form, and it exits normally, and then the control reenters to protected-form again, cleanup forms are no longer invoked. Supposedly it has already committed irreversible action. The second execution of protected-form may access to the already released resources and causes an error; it's up to the user to deal with the consequence. I know it is a pretty leaky abstraction. But executing cleanup forms in the after thunk won't coexist with continuation based coroutines. On Sat, Oct 8, 2022 at 11:56 PM Marc Nieper-Wißkirchen < marc.nie...@gmail.com> wrote: > John Cowan suggested that SRFI 226 should include a version of Common > Lisp's unwind-protect suitable for Scheme. > > In [1], I replied after some discussion with the following proposal > for a definition of a Scheme unwind-protect: > > (define-syntax unwind-protect > (syntax-rules () > ((unwind-protect protected-form cleanup-form) > (call-with-continuation-barrier > (lambda () > (dynamic-wind > (lambda () (values)) > (lambda () protected-form) > (lambda () cleanup-form))))))) > > As I think it is essential to get this famous form right when included > in a fundamental SRFI like SRFI 226, I would like to hear more > opinions on the above form. > > (It should be noted, that Scheme procedures like > `call-with-input-file` are not based on unwind-protect semantics.) > > Should there be no consensus on unwind-protect, it is probably better > to reserve an extra SRFI for it (which, in turn, can depend on SRFI > 226). > > Thanks for taking a look, > > Marc > > -- > > [1] https://srfi-email.schemers.org/srfi-226/msg/20888154/ >