Subject: Re: Trouble with CALL/CC
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1997/01/23
Newsgroups: comp.lang.scheme
Message-ID: <5c7ap1$78c@tokyo.engr.sgi.com>

Chris Bitmead <Chris.Bitmead@Alcatel.com.au> wrote:
+---------------
| So is my understanding right? Is the escape procedure dead once
| call/cc returns?
+---------------

*NO!*  ...and that's one of the things that makes implementation
of full Scheme continuations "interesting" in a C stack environment.
Consider the following (and ignore the fact that we could do it more
simply by making "foo" be a closure over the let):

	> (define foo #f)
	> (let ((counter 0))
	    (call/cc (lambda (k) (set! foo k)))
	    (set! counter (1+ counter))
	    counter)
	1
	> (foo)
	2
	> (* 17 (+ 12 (foo) 29))
	3
	> (foo)
	4
	> 

See??!?  No way can you do that with a simple setjmp/longjmp!

For this reason, most (all?) Schemes that use the C stack for
procedure calls implement call/cc by copying the *entire* stack
(and the current active registers, don't forget them!) into
the heap as part of the continuation object, and then if this
continuation is ever invoked, they overwrite the then-active
stack (and registers, including the stack pointer) with the
saved heap information, and "return". (...*without* altering
the saved heap object!)


-Rob

p.s. Because this can be quite expensive when the stack is deep,
many C-based Schemes also provide a more limited non-local break,
sometimes called "call/ec" (call with escaping continuation),
which mirrors the normal "use-once" setjmp/longjmp.

p.p.s. Note that if full call/cc is used when the stack is fairly
shallow, e.g., for implementing (nearly) top-level coroutines or
"processes" or the like, it's actually not *too* expensive...

-----
Rob Warnock, 7L-551		rpw3@sgi.com
Silicon Graphics, Inc.		http://reality.sgi.com/rpw3/
2011 N. Shoreline Blvd.		Phone: 415-933-1673  FAX: 415-933-0979
Mountain View, CA  94043	PP-ASEL-IA