Continuations Are Worth Being Hot

Steve has noticed, via Don Box, that continuations are getting popular. I can tell you from personal experience that there is a ton of value to continuations in multiple arenas, not the least of which is web serving.

Apache Cocoon has supported continuation-driven application flow for its web applications for quite some time now, either using Flowscript (ECMAScript with continuations, done in Rhino), or via JavaFlow (which is currently beyond my ken). Flow makes it amazingly easy to model complex behavior using the standard programmer-friendly syntax of loops, conditionals, and function calls. It’s brilliant!

And in some other work I’m doing right now, I desperately wish for continuations in C#. I am attempting to asynchronously decode buffers into message structures, and the painful callback-based approach used by .NET’s Begin/End/IAsyncResult approach makes it extraordinarily difficult to code. In order to avoid blocking a thread, I am forced to either stitch together a confusing chain of callbacks, or read data in a larger blocks. The problems with the former are lack of understandability and difficult debugging, and the problem with the latter is that message parsing often requires small chunks to be read to determine how much more is to be read to complete the message.

I yearn to be able to write code like the following, despite my unwieldy made-up syntax and lack of error checking.

`Message Decode(Stream stream) {    BinaryReader reader = new BinaryReader(stream);    Message msg = new Message();

   msg.Foo = Continuation.CallWithCurrent(reader.ReadInt32);    msg.Bar = Continuation.CallWithCurrent(reader.ReadInt32);

`

return msg; }

Then, the BinaryReader would support something like this:

void ReadInt32(Continuation continuation) {    // Set in the constructor.    this.stream.BeginRead(this.buffer, 0, 4, delegate(IAsyncResult result)    {       this.stream.EndRead(result);       int result = this.ConvertBufferToInt32();       continuation(result);    }); }

I could write my deserialization function as a nice procedural list of instructions, and not have to worry about blocking a thread while I wait. You could, of course, push the continuation call farther down the stack into the stream or socket or from whatever is being read.