BYVoid / continuation

JavaScript asynchronous Continuation-Passing Style transformation (deprecated).
Other
388 stars 42 forks source link

Portable continuations? #37

Open sanity opened 9 years ago

sanity commented 9 years ago

Are continuations portable? Specifically, could a continuation be serialized and sent across the network to be resumed elsewhere?

If that were possible you could potentially do some very interesting stuff with breaking down the barrier between client and server. I experimented with this idea a few years ago using Scala (which has a compiler plugin that does something similar to this project), you can learn more about these ideas here: http://swarmframework.org/

BYVoid commented 8 years ago

Serialization of code is not a part or purpose of this project. You can compile the code into plain JavaScript and use some other (maybe) existing library to do so.

sanity commented 8 years ago

It's more that the data representing the state of the continuation is serialized, rather than the code being serialized. Portability is a very useful property of continuations. For example, it could be used to break down the barrier between JavaScript running client side and server side.

pimterry commented 8 years ago

@sanity I was looking at this too, but I'm pretty sure that's impossible in JavaScript, sadly. There's a few objects that I believe it's impossible to reliably serialize, and there's no serious reflection API for getting low-level info from a closure to help you out.

For example, to take some fairly common JS code:

function F() {
  // [...some operation with side effects here, so you can't just rerun the constructor...]

  var x = 1;

  this.doSomething = function () {
    this.myProperty = x;
  } 
}

var f = new F();

You can't reliably safely serialize and deserialize f. You can get at the prototype and the properties from the object to do the basics, and you can get f.doSomething, but even if you serialize that method's body, I don't think you can get a reliable mechanism to grab 'x' and recreate it in doSomething's closure during deserialization. Even knowing it exists requires you to turn doSomething back into a string and reparse it yourself, and analyse the variables referenced within.

You can sort of get at it in this small example with some foolish hacks (parsing the whole constructor, comparing to the definition of doSomething, and going from there), but you can come up with more complex examples in the same vein where it's absolutely totally impossible (i.e. if x is outside both the constructor and the current scope). There's sadly no nice reflection APIs that let you get at the closure itself, so far as I can find, to reflect on what exactly it has references to, or to populate new closures when deserializing.

Without this you can easily pass function bodies and states around to share continuations, but not the variables on their stacks, which I think totally eliminates all the interesting uses of this (to my knowledge).

It might be possible to do something like this if you require any users to configure full serialization/deserialization methods for any very non-primitive objects that might be involved, but that's going to be hard work, and very unwieldy to use. I've seen a few mentions of improving the APIs around this in future as part of the ES7 spec, but I can't seem to find any concrete references to that, and it certainly isn't something that's widely available. Sorry!