Live data from Hacker News

What Does "With Continuation" Mean? (2020)

forum.snap.berkeley.edu

21–30 of 60 posts

Re: What Does "With Continuation" Mean? (2020)

#21

I took a Scheme programming class where we did tons of stuff with continuations. I got obsessed and wrote all kinds of weird code. I even started using continuation passing style in Python. It was a dark time. Looking back, none of that code makes any sense at all. When I think back to my days of mucking around with call/cc my main emotion is relief that I’ve forgotten how it works. It’s a load off my mind

Continuation passing style is mostly a good tool for writers of compilers, and perhaps interpreters.

It's very, very similar to single-static-assignment (SSA) style that will be more familiar to people coming from imperative languages.

Re: What Does "With Continuation" Mean? (2020)

#22

So there’s a funny thing this doesn’t touch on: the semantics of call/cc is genuinely confusing to understand! There’s a related construct that’s much more legible and has a much easier to understand: call with delimited continuation! Oleg K wrote a very articulate piece about this some long time ago https://okmij.org/ftp/continuations/against-callcc.html

Approximately everything by Oleg is great!

We half-jokingly considered renaming our Sydney Computer Science Paper Club to 'Oleg Fan Club'.

Re: What Does "With Continuation" Mean? (2020)

#23
post #12

I don't know whether it helps, but here's another explanation that doesn't involve a visual programming language: First, imagine that procedures (or functions) are first-class values, like in some languages are called "anonymous functions", "closures", "lambdas", etc. Now imagine that every procedure call is effectively a goto with arguments... and the familiar part about being able to return from that procedure, to…

An alternative way to look at for C/C++/pascal/… programmers it is by looking at the return keyword not as a keyword, but as an implicit argument that’s a pointer to a function. Imagine this would work:

   global fooBack
   global barBack
   main() {
     print foo()
   }
   foo() {
     fooback = return
     bar()
     return “foo”
   }
   bar() {
     barBack = return
     if randomBool
       fooBack(“bar”)
     else
       return “bar”
   }
and that, 50% of the time, woud print “bar”.

In a C-like system with a call stack, that would give you a nicer setjmp (still with quite a few limitations). Systems with true continuations would allow code to call ‘up the stack’ for example if main were to call barBack in the scenario above. That wouldn’t work in C as bar’s stack frame wouldn’t exist anymore.

Re: What Does "With Continuation" Mean? (2020)

#24

Earlier quoted context omitted.

Continuations aren't equivalent to closures.

Continuations are closures. Closures aren't continuations. Though one can build continuations out of closures by converting code into continuation passing style, which makes continuations explicit, and then `call/cc` is trivial, since all it does is pass (to its function argument) its [now-explicit, after CPS conversion] continuation, thus reifying it.

Continuations are just closures in cps. Closures are just functions plus an environment parameter. Functions are just gotos plus a link pointer. Yet each abstraction is more than the sum of its components.

Re: What Does "With Continuation" Mean? (2020)

#25

Earlier quoted context omitted.

Continuations are closures. Closures aren't continuations. Though one can build continuations out of closures by converting code into continuation passing style, which makes continuations explicit, and then `call/cc` is trivial, since all it does is pass (to its function argument) its [now-explicit, after CPS conversion] continuation, thus reifying it.

Ehh. I think it makes it a lot harder to understand what a continuation is if you say they’re closures. Continuations capture the stack. Closures capture variables.

It is not wrong though. Once you reify the return continuation, a continuation is really just a closure, the stack is implicitly recovered by recursively following the captured return continuations. And with closures you do not necessary have a stack anyway but any arbitrary directed graph.

Re: What Does "With Continuation" Mean? (2020)

#26
post #11
post #10

Earlier quoted context omitted.

In case first-class continuations scare anyone away from Scheme: you probably will never use it directly in practice, unless you're doing something very unusual that happens to really need it. For example, say you have a really hairy AI search algorithm, capturing a continuation happens to make backtracking easier. Or you're implementing another language or DSL in Scheme, and you use first-class continuations to impl…

I’m having trouble recalling, call cc just fixes the stack, right? If you mess with the heap, that sticks around? The backtracking example is a good one. I vaguely remember needing to be careful about global state, or visible in a given context. It’s not awful, but a little tricky.

There isn't necessarily a stack with call/cc, the model is that activation frames are heap allocated[1] and can be arbitrary composed. Normally they would be GC collected when a function returns, but call/cc exposes the caller activation frame (+ a function representing the rest of the caller function body) as a first call object, that once captured prevents it from being garbage collected. The stack is recovered by realizing that activation frames have a reference to the calling function activation frame (which is passed to every function as an implicit parameter).

Also an activation frame per se is immutable, but not the objects referenced by it, so all modifications are preserved when invoking a continuation.

[1] this is just a model, in practice there are many ways to implement this that optimize for the common FIFO allocation discipline.

Re: What Does "With Continuation" Mean? (2020)

#27
Continuations are also the backbone of co-routines in Kotlin and has first class support. One nice feature of the coroutines framework is that they made it really easy to adapt existing asynchronous frameworks in Java (there are many) and on other platforms. The list of supported frameworks includes things like reactive Java, vert.x, spring webflux, Java Futures. And that's just the JVM. If you are using kotlin-js in the browser or on node.js, promises and async/await are covered too. And on IOS, coroutines also do the right thing with e.g. garbage collection and other mechanisms in IOS.

Most of this stuff is supported via extension functions. But for asynchronous things that aren't supported it's really easy to adapt them yourself with the suspendCancellableCoroutine function. This is a suspending function that takes a function with a continuation as the parameter. Inside the function you do whatever needs doing and handle your callbacks, futures, awaits, or whatever and call continuation.resume, continuation.resumeWithException, or continuation.invokeOnCancellation as needed (which sadly is not a feature every async framework or language supports).

With a few small extension functions you can pretend most things are nice kotlin suspend functions and not deal with the spaghetti code typically needed otherwise. E.g. Spring Flux is an absolute PITA in Java because of this and essentially effortless in Kotlin. Your code looks like normal kotlin code. Nothing special about it. All the flux madness is shoveled under the carpet.

In the same way the new virtual threads in Java are supported trivially because all of that is exposed via the existing Theading and Threadpool APIs. So, you can just dispatch your co-routine asyncs and launches as virtual threads via a dispatcher that you create with a little extension function on Threadpool. Most of this stuff "just works" out of the box. There's a lot of confusion on this topic in the Java community. For Kotlin this is just yet another way to do async stuff that joins a long list of existing other ways. It has its pros and cons for different use cases and is there if you need it. No big deal but very nice to have around. I've not found any use for it yet and we're on Spring Boot and java 21. We already have everything asynchronous and non blocking.

Re: What Does "With Continuation" Mean? (2020)

#30
post #22

So there’s a funny thing this doesn’t touch on: the semantics of call/cc is genuinely confusing to understand! There’s a related construct that’s much more legible and has a much easier to understand: call with delimited continuation! Oleg K wrote a very articulate piece about this some long time ago https://okmij.org/ftp/continuations/against-callcc.html

Approximately everything by Oleg is great! We half-jokingly considered renaming our Sydney Computer Science Paper Club to 'Oleg Fan Club'.

Hehe fun!

Yeah, delimited continuations have much saner semantics than undelimited ones. Partly because they’re always well defined

Post reply on HN