

An argument against call/cc (2012) - luu
http://okmij.org/ftp/continuations/against-callcc.html

======
jrapdx3
FWIW, the behavior of call/cc, et. al., is implementation dependent, and
memory leakiness varies considerably.

I tried the "memory leak" tests in Chicken (4.9.1) using the CSI REPL. The
only modification made to the example "gen-leak.scm" was uncommenting the
(display ...) line in (print-stream ...).

The result with (print-stream #f (gen-stream ones)) was non-terminating
production of "1", like an infinite loop, but it _didn 't run out of memory_,
even after running >10 minutes in a resource-constrained VM.

I'm not familiar enough with how call/cc is implemented in Scheme48 vs.
Chicken to comment in detail, but I'm sure there are substantial differences.
The Chicken site ([http://call-cc.org](http://call-cc.org)) provides quite a
bit of info about its own implementation.

------
ssp
If you generalize labels so that they become first class, then call/cc can be
written in terms of goto.
[http://ssp.impulsetrain.com/goto.html](http://ssp.impulsetrain.com/goto.html)

~~~
WallWextra
It's longjmp.

~~~
mostly_harmless
not quite. It is similar to longjmp except that this can jump down the stack.
these labels can be jumped to even after the function returns

~~~
lisper
Right. The way it was explained to me years ago that really stuck with me is
that one way to implement call/cc is to copy the stack onto the heap.

(And another way to do it is to simply allocate all your function call frames
on the heap to begin with and not have a stack. Then call/cc is essentially
free, but you need a really good incremental garbage collector because now
every function call conses.)

~~~
ssp
Does copying the stack really work? What if some local variable changes in
between the call/cc and calling the continuation? If the stack is a copy, that
change will not be reflected when the continuation runs.

~~~
lisper
That's a very interesting point. AFAICT, the Scheme standard doesn't actually
say what should happen in this case. But here's what e.g. Chibi scheme does:

    
    
        > (let ((x 0)) (list (call/cc (lambda (f) (set! x 1) (f 2))) x))
        (2 0)

~~~
ssp
The equivalent in Oort produces:

    
    
        localhost:~/oort/examples% ../oort callcc2.nl 
        2
        1
    

as expected since Oort uses heap allocated activation records.

The Oort program:

    
    
        typedef continuation_t = fn (p: int32) -> void;
        
        call_cc (fun: fn(k: continuation_t) -> void) -> int32
        {
            retval: int32;
        
            fun (fn (v: int32) -> void {
                retval = v;
                goto current_continuation;
            });
            
            // If fun returns without calling the continuation,
            // then just return 0
            return 0;
        
        @current_continuation:
            return retval;
        }
        
        x: int32 = 0;
        
        print call_cc (fn (k: continuation_t) {
            x = 1;
            k (2);
            });
        
        print x;

------
davexunit
Delimited continuations are better. Guile has them, and they rock. It's very
easy to implement coroutines and other control flow structures with them.

~~~
judk
This is covered in the article

~~~
agumonkey
I wonder how much that paper influenced guile delimited continuations support.

------
gte525u
This seems a bit ironic to see this posted on one of the few sites on the
internet that use continuations as it's primary control flow mechanism.

