Created by rompf on 2009-06-05. Updated: 2010-08-12, 15:51

Scala 2.8 will support continuations, a powerful control flow abstraction. Among other things, continuations allow using callback oriented, event driven APIs in a direct, statement-by-statement style.

This will potentially simplify a number of programming tasks:

doing asynchronous I/O using Java NIO

using executors and thread pools

handling cross-request control flow in web applications

There won't be any new API's for these use cases in Scala 2.8, but we expect them to emerge once the underlying continuation machinery is in place.

A Glimpse of Shift and Reset

A continuation, "captured" at some point in a program, embodies "the rest" of the program at that certain point. The interesting part is that continuations can be treated as regular function values, e.g. saved in a data structure and invoked only later, or not at all, or multiple times. Continuations in Scala differ from those available in languages like Scheme or ML, in that Scala's continuations are composable (or "delimited"). This means that they embody not the whole rest of the program, but just a partial rest, up to a programmer-defined outer boundary.

Continuations are manipulated by means of two primitives, shift and reset. Calling shift captures the current continuation, and reset defines the boundary up to which the continuation reaches. Here is an example:

reset { ... shift { k: (Int=>Int) => // the continuation k will be the '_ + 1' below k(7) } + 1 } // result: 8



Of course, shift and reset are library functions, not new keywords. They also need not appear as close together syntactically. In fact, corresponding uses of shift and reset may occur in completely unrelated methods. The type system ensures that nothing goes wrong and requires every method that contains a free shift to be marked with a type annotation @cps on its return type. For many cases though, this type annotation is inferred automatically, transparent to the programmer.

def foo(): Int @cps[Int,Int] = { // could leave out return type shift { k: (Int=>Int) => k(7) } + 1 } reset(2 * foo()) // result: 16

Here is another example that illustrates the connection to callback driven API's:

import java.util.{Timer,TimerTask} val timer = new Timer() def sleep(delay: Int) = shift { k: (Unit => Unit) => timer.schedule(new TimerTask { def run() = k() // in a real program, we'd execute k on a thread pool }, delay) } reset { println("look, Ma ...") sleep(1000) println(" no threads!") }



If you feel adventurous, try out the pre-release continuations plugin for the Scala compiler yourself (available from the source repository). To learn all the gritty details about how continuations are implemented in Scala 2.8, have a look at the corresponding paper (accepted at ICFP'09).