guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: continuation efficiency


From: Marius Vollmer
Subject: Re: continuation efficiency
Date: 07 Jul 2001 13:46:20 +0200
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.0.102

address@hidden (Thomas Bushnell, BSG) writes:

> Marius Vollmer <address@hidden> writes:
> 
> > Contrary to what I said in an earlier post, I now think that cleanup
> > actions _are_ important in reaction non-local exits.  Using
> > dynamic-wind can not provide these cleanup actions since the `leave'
> > thunk can not know whether the control flow will return eventually.
> > Thus, dynamic-wind is only useful for changes to the system that have
> > a dynamic extent.  Examples are setting global parameters like the
> > current ports or the current module (eek!).
> 
> I agree that they are important, but you have missed the right way to
> use dynamic-wind I think.
> 
> If you want to prevent a call into a dynamic-wind, you need to provide
> an "enter" thunk that errors out on any call but the first.  

Yes, but the point of escape-protect is not to prevent entering the
dynamic context more than once, it is about preventing it to be
entered once you have promised that this wont happen in the future.
The promise is made by invoking a escape continuation.

Thus, the error checking is there to enforce the defined semantics of
escape-protect.  Part of that semantics is that there is a distinction
between switching from one dynamic context to another with the
intention to switch back later (as for coroutines), and leaving a
dynamic context with the promise not to come back (as for non-local
aborts in reaction to an error).

The former non-local transfers of control are the job of call/cc and
the switching of dynamic contexts can be observed and implemented with
dynamic-wind.  The latter is the job of call/ec and can be observed
with escape-protect.

Thus, my main point is that it is useful to distinguish between
context switches for coroutines or backtracking, etc; and leaving a
context for sure.  Call/cc can be used to implement both kinds, but
using call/cc for both does not allow the programmer to express its
intention.

I think that this distinction is useful since cleanup actions can be
costly, and it can be especially costly to undo them, if that is at
all possible.  A network protocol comes to mind that you want to abort
cleanly in the case of error.  It might be hard to resume that
protocol when you find out that your dynamic context is re-entered.
Throwing an error in re-entering will make using your code in a
coroutine impossible, although there is nothing fundamental to it that
demands this.  Thus, I'd say that you want to know whether control is
coming back, or not, at the point of the control leaving.

With call/cc you can't be sure that it is only used to implement
context switching (or suspend/resume) scenarios, but we can at least
specify that a programmer should only use call/cc for "suspend/resume"
or "suspend/multiple-resume" scenarios.  Yes, it's a fundamental
change to the Scheme semantics.


One alternative is to rely on the garbage collector to clean up after
you, using guardians or similar mechanisms.  I don't think this is a
good alternative since the GC is asynchronous and not guaranteed to
run at all.  Relying on it for interaction with external objects like
network connections or visible windows does not feel right to me.


Another alternative is to couple escape-protect with error handling
and do away with the special semantics of call/ec.  escape-protect
would catch all errors, run the cleanup actions, and then decline to
handle the error (passing it on the next most recently established
handler).  But this would be a change to the order in which cleanups
and error handlers are run.

With the proposed behavior of escape-protect and call/ec, error
handlers are run first and only when a error handler decides to
perform a non-local exit beyond a cleanup handler is that cleanup
handler run.  An error handler might invoke a `restart' that it has
coordinated with the code that signalled the error (`invoking a
restart' is the CL term for resuming from a trap or fault) in which
case the cleanup handler should not be run since the dynamic context
has not been aborted.

When escape-protect is implemented by catching all errors, it will
potentially and incorrectly perform its cleanup actions before the
real error handler invokes the restart.  Or a more recent error
handler than the one installed by escape-protect will perform a
non-local exit, skipping the cleanup actions.  Thus the interaction
between cleanups and error handlers is not correct.


The test to see whether there is any merit to my view is to write up a
SRFI and let the Scheme heavy weights rip it to shreds.  I know that
the interaction between call/cc and dynamic-wind is controversial in
the Scheme community...


> call/ec might be a useful performance enhancement (if the interpreter
> knows about it specially, and it's not just a wrapper around call/cc),
> but it doesn't provide any particularly useful extra semantic that
> call/cc and dynamic-wind don't already provide perfectly well.

That's the key point where I disagree: I don't think that call/cc and
dynamic-wind can provide the semantics perfectly well since they don't
afford the programmer to express its intentions, cross-module.  Every
isolated body of code can implement its own (correct) way to implement
escape-protect, but these implementations need to play together in a
useful way when those codes are combined.  That's why I think that
escape-protect needs to be provided by the base system (or a
well-known library).  So that everybody uses the same identical
machinery.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]