[plt-scheme] Re: "unwind-protect" for PLT Scheme?

From: Elena Garrulo (egarrulo at gmail.com)
Date: Mon Aug 10 16:22:57 EDT 2009

I've found this documents which could be of interest:

Dorai Sitaram. "Unwind-protect in portable Scheme". Scheme Workshop
2003. November 2003:

Here is a critique from Kent Pitman about the lack of a proper
"unwind-protect" in Scheme:


2009/7/5 Eli Barzilay <eli at barzilay.org>:
> On Jul  4, Shriram Krishnamurthi wrote:
>> You only need the before-thunk argument to do something if you have
>> continuations somewhere deep within the body expression.  (But note
>> that even if you don't use continuations, you just might use a
>> library function that does.)  As long as neither you nor a library
>> does, you can pass something trivial as before-thunk, such as void.
>> That reduces to being the same as Lisp's unwind-protect.
> Sorry to add another post on this, but I'll try to make a quick
> summary of this whole thing in plain English (as much as I can call
> what *I* write "plain English"):
> * When no continuations are involved, `dynamic-wind' is perfectly fine
>  as is, and you can set up the resource either in the before thunk,
>  or before the whole call:
>    (let ([foo (open-output-file ...)])
>      (dynamic-wind void
>                    (lambda () ...do stuff with foo...)
>                    (lambda () ...close foo...)))
>  or
>    (let ([foo #f])
>      (dynamic-wind (lambda () (set! foo (open-output-file ...)))
>                    (lambda () ...do stuff with foo...)
>                    (lambda () ...close foo...)))
> * When continuations are involved, then control can jump into or out
>  of the main thunk, and you have several options to choose from.
>  Here the before thunk becomes important since it can be called not
>  just once, but several times -- once when it starts, and a pair of
>  after-before calls for each jump out of and back into the main
>  thunk.
>  Just ignoring this makes it possible for your code to run into
>  problems that are similar in nature to writing code that is not
>  thread-safe: in both cases the problem is not in your own code, but
>  in the way it is being called or in the way library calls it
>  performs behave.  And this analogy carries over to how people deal
>  with it: lots of user code just ignores the whole issue, but you
>  need to be more careful if you're writing some library, or parts of
>  the core language.  [`call/cc' is notorious in exposing all kinds of
>  things about how things are implemented (for example, IIRC there was
>  a point in the (distant?) past where you could squeeze two different
>  behaviors out of mzscheme's `map' function because the
>  implementation was optimizing uses with a few functions).]
> * Options for dealing with this are:
>  - Ignore the whole thing, and use the first form above.
>  - Arrange for the resource to be properly opened and closed on the
>    before/after thunks -- which means that you need to make sure
>    that, for example, you open the file in `append' mode so when
>    jumping out and back in the resource will be recreated.  Of
>    course, this depends on the code doing something simple, like just
>    writing to the file.
>  - Forbid re-entry: you make a before thunk that remembers if it was
>    already called -- if that's the case, then you know that somehow
>    control went out and back in, and you make it throw an appropriate
>    error.  This can be convenient if, for example, it is meaningless
>    to use the resource after it was already released.
>  - Intentionally avoid creating and releasing the resource in a
>    `dynamic-wind', so it will only be released when control leaves
>    normally.  An example for this would be:
>      (let ([foo (open-output-file ...)])
>        (begin0 (...do stuff with foo...)
>          (...close foo...)))
>    or better:
>      (let ([foo (open-output-file ...)])
>        (define (close-foo) ...close foo...)
>        (with-handlers ([(lambda (x) #t)
>                         (lambda (e) (close-foo) (raise e))])
>          (begin0 (...do stuff with foo...)
>            (close-foo))))
>    This works if when control happens to go out, it will also go back
>    in, so eventually control leaves as usual.
>  - There's a number of variants on these and subtle points involved
>    etc.
> --
>          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
>                    http://barzilay.org/                   Maze is Life!

Posted on the users mailing list.