Continuations and return context

leo on 2005-07-10T21:17:06

A correction foremostA remark WRT the paragraph mentioning type checking in my first ewaa journal. It was caused by me misinterpreting the type conversion specs in pdd03. We are now doing full type conversion, which makes argument passing strictly positional. That's very likely the expectation of our users anyway. In the old scheme calling a subroutine:

foo(pmc b, str a) # pseudosyntax to denote argument types

just worked, despite the sub was defined as:

.sub foo
.param str a
.param pmc b

Looks weird, but was really used, probably more by accident then for some good reason. Now you get the first argument converted to a string and the second as a new string PMC.

Continuations and return context

As Dan describes in his blog, there is not much difference between a subroutine call and the invocation of a continuation. Both can return results to the caller. A nice example provided by Piers from Parrot's tests (yeah, number 13) contains something like:

x = choose([1, 3, 5])
y = choose([1, 5, 9])
if (x * y != 15)
fail()

Above is vastly simplified, because the choose function calls capture their continuations and call a try closure that either backtracks via the saved fail hook or delivers the next item from the passed in choices array. Anyway the interesting thing (for a proper implementation of continuations) is, that there are mupltiple continuations that like to return either the next x or y, when invoked indirectly via the fail function. These continuations are not only returning to different program locations they are also returning different results.

In the source we got this line:

our_cc($P3) # $P3 being one of the next choices

where eventually the next result for choose is to be returned to the main program. It looks like a plain subroutine call, but invokes the passed in continuation and ends up, where one of the choose calls had left off.

This means that creating a full continuation still needs to copy the context structure (which contains also the current return results location). A return continuation can just contain a pointer to the refered context.

After having implemented this all now, the rather complicated tests (p6rules, streams), which are using continuations as well as coroutines are passing within my branch (I didn't look at other failing tests yet, but just converting explicit register usage for call setup to new conventions should fix almost all). These tests are of course passing in Parrot svn trunk true, but now (for the most common case of invoking a return continuation) no context is copied at all, it's just a matter of putting the pointer of the captured context into the interpreter.

The official way to do call/cc is still unchanged, it's:

.include "interpinfo.pasm"
cc = interpinfo .INTERPINFO_CURRENT_CONT

This usually means that you need a helper subroutine, where you capture the continuation (and pass it along somewhere for later usage), it's OTOH a well defined usage of continuations in e.g. scheme. When things are settling, I'm sure that we can provide some shortcuts for capturing continuations inside the same sub (or context) too.

And implementing want or similar is of course simple now, as the get_results opcode is emitted before the subroutine invocation, and is therefore available for plain function returns as well as for continuations that return a result. Both can return what the caller wants, because the information is present in the context.