javascriptcschemecontinuationscallcc

Is CallCC an improved version of goto?


My background is Javascript, Python & a bit of Haskell. I am trying to understand callCC, there are many explanations but I can't find them trivial & I came across this https://www.cs.bham.ac.uk/~hxt/research/Logiccolumn8.pdf and I felt like I almost got it but I need some help to understand C code.

Below is the Code for Jumping back into a function in GNU C.

void *label_as_result() {
     return &&L;
  L: printf("Jumped back into the function. \n");
}

main () {
    void *p;
    p = label_as_result();
    printf("The function returned; now jump back into it.\n");
    goto *p;
}

What does return statement do in label_as_result function? Does p in main store the stack frame in heap & the instruction line where it is stopped? Jump back to function means create a stack frame again and continue from where we left?

Below this code there is paragraph

But in a language with first-class functions and callCC, no such implementation restrictions apply. Just as with the label as a result in C, we can return a continuation introduced by callCC from a function so as to jump back into the function. When we did this with goto, the stack was smashed, but with callCC the function just returns again. Consider the following function

 λ(). callCC(λk. λx. throw k (λy. x))

The continuation k is returned as part of the result, roughly analogous to returning a label as the result in C.

What does stack was smashed, he meant stackoverflow can happen if you use goto? How callCC is getting around this problem using trampolining?

As many say callCC gives Early return semantics that means is it like yield in python or Javascript? Is it possible to write callCC in Javascript using yield?

How I conceive the above code in Javascript

function* label_as_result() {
    yield () => console.log("Jumped back into the function.");
}

p = label_as_result().next().value;
console.log("The function returned; now jump back into it.");
p();

It can even simple be written without any generators concept as

function label_as_result() {
    return () => console.log("Jumped back into the function.");
}

p = label_as_result();
console.log("The function returned; now jump back into it.");
p();

That means callCC is a function that returns a continuation but all other functions take continuations. Continuations are like Undecided code that need to be performed in future but callCC is like predefined code that needs to be performed in Future? (I am talking in perspective of a framework and the user's code)


Solution

  • What does return statement do in label_as_result function?

    It returns the address of the instruction labelled L. That is, it returns the address of where the code the compiler generated for printf("Jumped back into the function. \n"); is stored in memory.

    Does p in main store the stack frame in heap & the instruction line where it is stopped?

    No, it stores the instruction line where the L label is. That's all it stores.

    Jump back to function means create a stack frame again and continue from where we left?

    No, it means a single jump and nothing else - no stack manipulation. The control flow jumps to the line labelled L, but nothing else changes. The stack remains unchanged.

    What does stack was smashed, he meant stackoverflow can happen if you use goto?

    Underflow, actually. When label_as_result is called, a frame is pushed to the stack. When it returns, that frame is popped. Then we jump to L, execute printf and then reach the end of the function, which will pop the stack again. So in the end the stack was popped more often than it was pushed.

    How callCC is getting around this problem

    By actually doing what you assumed the C code was doing: Saving and restoring the stack instead of just jumping to a code line while keeping the stack the same.

    As many say callCC gives Early return semantics that means is it like yield in python or Javascript?

    They're alike in the sense that they both give you a type of early return and they can be used for some of the same things. You can think of yield as a more specialized tool meant to provide a simpler way to achieve some of the use cases of callCC.

    Is it possible to write callCC in Javascript using yield?

    No, but it's possible to write yield in Scheme using callCC. callCC is strictly the more powerful of the two.

    How I conceive the above code in Javascript

    The actual C code isn't something that you can replicate in JavaScript (other than by building a mini-VM with its own stack) because JavaScript doesn't allow you to destroy the stack like that.

    A non-broken version that doesn't destroy the stack could be accomplished by returning a function from label_as_result as you do in your second code sample.

    That means callCC is a function that returns a continuation

    callCC is a function that calls another function with the current continuation. That can be used to return the continuation.

    Continuations are like Undecided code that need to be performed in future

    Sure, except I wouldn't say "need" here. You don't have to invoke the continuation (or you could invoke it more than once even).

    but callCC is like predefined code that needs to be performed in Future?

    Not quite sure what you mean here, but that doesn't sound right. callCC is a function that gives you access to the current continuation.