Subject: Re: faking dynamic-wind ?
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 22 Dec 2000 04:08:32 GMT
Newsgroups: comp.lang.scheme
Message-ID: <91uk40$f165j$1@fido.engr.sgi.com>
<stephan@pcrm.win.tue.nl> wrote:
+---------------
| Indeed, if you wants to mix both uses of call/cc, you soon
| find out that this means that you cannot use dynamic-wind
| for try..finally purposes. 
+---------------

You can't anyway, since you'd want the unwinding to *stop* when it hits
the "after" clause that was being used for the "finally" part. That is,
consider this naive/obvious implementation of CL's "unwind-protect",
which assumes that all system errors invoke a continuation captured
in the top-level REPL (which is the case in many implementations):

	> (defmacro unwind-protect (protected-form . cleanup-forms)
	    `(begin
	       (call/cc
	         (lambda (break)
		   (dynamic-wind
		     (lambda () #t)
		     (lambda () ,protected-form)
		     (lambda () (break)))))
	       ,@cleanup-forms))
	> (unwind-protect (/ 1 0)
	    (print "This prints anyway")
	    17)
	/: division by zero
	This prints anyway
	17
	> 

However, R5RS clearly says:

	The effect of using a captured continuation to enter or exit
	the dynamic extent of a call to "before" or "after" is undefined.

So you can't legally do that [even though it works in the particular
implementation I tried it in].

I ran into exactly this problem when implementing a private REPL inside
a script that was supposed to be portable between MzScheme and SCM. SCM
did what I had hoped for, but MzScheme barfed on a continuation being
invoked in the "after" thunk -- it called the "after" thunk again!!
[Hey, "undefined" behavior can be *anything*, right?] Thankfully, the
Rice guys fixed the problem in the next release.

+---------------
| (Since Scheme isn't clairvoyant and cannot guess in which of
| the two meanings you want to use call/cc.)
| Which means that you probably end up:
| 1. not using the real dynamic-wind
| 2. write your own call-with-winding-continuation + fake-dynamic-wind
| 3. do exceptions with the new call/wc and use the original call/cc
|    for threading
+---------------

It's worse than that. The Scheme spec makes no guarantee that program
errors will invoke a [captured top-level] continuation, thus you have
no guarantee whatsoever that, say, "(/ 1 0)" or "(* 5 'foo)" will even
*do* an unwind!!


-Rob

p.s. Precisely because MzScheme *was* designed (or evolved) to support
instructional programming, with DrScheme (and its MrEd-based GUIs) allowing
execution of arbitrary student code yet wanting to catch all errors itself,
MzScheme exception-handling system *does* interact fairly nicely with both
call/cc & dynamic-wind. But that's just one implementation, not the standard.

-----
Rob Warnock, 31-2-510		rpw3@sgi.com
Network Engineering		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		PP-ASEL-IA
Mountain View, CA  94043