Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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


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.)


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.


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)


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;




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: