Apologies if anyone has the opinion this is off topic.  I am sharing some
thoughts in case any one (perhaps myself) wanted to try to add
continuations to Neko or any similar system.

I am undecided if continuations are worth the effort?  Generators seem
quite useful, but could be implemented more efficiently than generalized
continuations.

I noticed that Lua supports coroutines (a potential use of continuations),
which they claim are useful for implementing multi-tasking on devices
which do not supporting pre-emptive multi-threading, or for lower overhead
multi-tasking:

http://lua-users.org/lists/lua-l/2007-11/msg00248.html
http://www.lua.org/manual/5.1/manual.html#5.2

Let's assume that even without the optimization below, that continuations
save an entire copy of the stack, then this overhead (other than latency
on initial save) will be insignificant for implementing coroutines when
the running time of the coroutines is long compared to time to save stack,
because the stacks will not be resaved each time the coroutines call each
other (alternating execution, i.e. cooperative multitasking).

Even with pre-emptive multi-threading, unless that is designed into the
browser (e.g. Google's Chrome) and server to aware of blocking on slow
resources (i.e. to pre-emptively multitask on such blocking), the
continuations could greatly simplify web coding:

http://en.wikipedia.org/w/index.php?title=Continuation&oldid=339611728#Continuations_in_Web_development

I can remember some of my complex nested blocks of Javascript code to deal
with asynchronous loading of code via XMLHttpRequest (or dynamically
loading the <script> tag), where the nesting could I presume be eliminated
with continuations.  Perhaps this can be solved (I think I did) with
closures and Continuation-passing style, or specialized shared state and
dispatch on asynchronous events, or separate thread for loading each
resource (again needing to maintain shared state negotiation), but it
might be less general or more convoluted.

I assume MMOG (massively multiplayer online games) may also have to deal
with asynchronous network resources.

> Am I correct that implementing continuations is similar to forming a
> closure, in that a copy of the current stack is saved to capture the local
> variables (execution context)?  Also the resume location in the executable
> statements is also saved.  If the function capturing the continuation
> contains a return statement (i.e. has any branch of execution that can
> return instead of resuming a captured continuation), then the entire stack
> history has to be saved also?

The optimization of not saving entire stack would not be available to HLLs
that support runtime evaluation of code statements, i.e. 'eval', in the
case that 'return' means return from the function containing the 'eval'
(as far as I know, there is no 'eval' that does that?).  Or at least the
entire stack would need to be saved by detecting at runtime the 'return'
from the containing function.

An orthogonal optimization is to save a pointer to captured location in
the stack, then incrementally save the portion of stack on the exit of
each stack block (e.g. function, either by 'return' or resume of a
continuation higher in the stack).  Then document that a continuation
captures the state of the stack (local variables) at each hierarchal
containing block exit, not at the statement for the capture.  This
optimization could avoid saving the entire stack in the cases where the
captured continuation is garbage collected before the entire stack is
unwound.  I assume the captured continuation is assigned to a variable, so
it can be resumed.  BTW, this is another example of the problem of
finalizers being called too late with garbage collection, and thus
aforementioned superiority of reference counting combined with specialized
Bacon's garbage collection (and maybe also weak references) for cleaning
up cyclical references:

http://lists.motion-twin.com/pipermail/neko/2010-January/002691.html

Another design tradeoff may be whether the continuation captures an
exclusive copy of the stack, or shared between all continuations in the
same stack fork.  I haven't really thought this out entirely, and it seems
to me this sharing might not be very common any way.  The algorithm would
be on exit of each stack block, check for a capture continuation pointer
deeper than current stack block, and if so save blocking being exited to
shared stack copy.  When a function call is made, then a new stack fork
has been created.

--
Neko : One VM to run them all
(http://nekovm.org)

Reply via email to