[Stackless] Continuations in Forth

Dirk-Ulrich Heise hei at adtranzsig.de
Tue Oct 31 13:26:25 CET 2000

Hi! I stumbled across this example for
the continuations by Cameron Laird:

def looptest(n):
    this = continuation.current()
    k = this.update(n)
      # continuation at "="
    if k:
        # resuming at "="
        del this.link

and, because i got that feeling that continuations
in stackless Python are similar to the return stack
tricks in Forth, i rewrote it in my Forth
(overly commented for Non-Forthers):

: ip>r r >r ;
 ( define a subroutine called "ip>r" :
    "r" gets the callers actual instruction pointer and ">r"  pushes
    it on the return stack one more time - in this
    subroutine, the instruction pointer of the caller
    is of course
    the return address of this subroutine. )
: exit rdrop ;
  ( drop the return address and return to what's next on the
     return address - in effect,  skip one return level )
: looptest ( n -- )
  ip>r ( push the instruction pointer to the return stack 
            -- it points to the following dup )
  dup ( duplicate value on data stack )
  if      ( test whether it's nonzero [destroys one stack op] )
    dup . ( duplicate and print top of stack )
    1 -      ( subtract one )
    r >r exit ( get return address, push it once more 
                    on the return stack, and do an "exit" -- which
                    returns to what we have put on the return stack
                    just before -- in fact, the address of the "dup" after
                   the ip>r above )
    rdrop  (clean up the r stack for an ordinary return )

and it worked... (don't try this at home unless you're
experienced in Forth or, alternatively, have
my extremely crash-resistant (and slow)
Forth-in-Python from 
www.egroups.com/group/synthetoforth )

Of course, a little cheating goes on in Forth: Forth has
no stackframes, but stores all local data on its data stack,
and sometimes on the return stack. 

Were there local variables, they would have to be "tied together"
with the return address entries on the return stack to form
a "state record" or a "continuation" that describes the
inner state of a function completely. I didn't need it in this
example because just one local existed in the Python source,
and it's passed to the continuation when it's called anyway.

The above Forth example clarified my understanding
of continuations, but i would say, the basic building block
for all of this is not the continuation, but the ability to manipulate
the return stack (in the Python case, the stack of stack frames)
from high level. Why is Forth capable of doing that?
*Because it has a second stack* - the data stack.
A program in a stack-frame-based machine model usually
keeps all local state in the stack frames, thus, when manipulating
it's stackpointer, it *loses all state info* (if you don't want to
pull dirty tricks with global variables), thus, its memory.

An idea would be:
Give the Python interpreter a second stack and some
functions or bytecodes to manipulate it, and re-implement
the continuations on top of return-stack-operations.
(which are, in Forth,">r","r>", and all the rest can be built on top
of those.)

What's your opinion?

Dipl.Inform. Dirk-Ulrich Heise
hei at adtranzsig.de
dheise at debitel.net

Stackless mailing list
Stackless at starship.python.net

More information about the Stackless mailing list