Thursday May 18, 2006

Will Continuations continue?

I spoke about dynamic language support and JSR292 at JavaOne today. I was quite disappointed that no one asked about continuations.

There are a variety of reasons why we haven’t implemented continuations in the JVM. High on the list: continuations are costly to implement, and they might reek havoc with Java SE security model. These arguments are pragmatic and a tad unsatisfying. If a feature is really important, shouldn’t we just bite the bullet?

I’ve thought about this a bit, and here’s my take on why we really shouldn’t add continuations to the JVM. It’s bound to stir up controversy and annoy people, which is a good reason to post it. By far he most compelling use case for continuations are continuation-based web servers.

A couple of weeks ago I was embroiled in a rather passionate argument about the relevance of continuation-based web servers at an academic retreat at Dagstuhl, Germany. This is an opportunity for me to write down my thoughts on that topic, as the two are closely linked.

The use case for coninuation-based web servers is simple. I want to book a hotel via the web. The web server asks: where? I say Alaska. I love polar bear rides. The server shows me a list of hotels in Alaska. I pick one, it shows me the details. I decide that maybe Alaska in December is too cold, so I clone the browser window, press back a couple of times, until I’m back to the question: where do you want to go today? This time I answer: Hawaii. I get a list of hotels in Hawaii, and pick one. Now I can compare the two destinations side by side.

Upon reflection, I decide to go to Alaska after all. When will I ever get a chance to go Polar Bear Back riding again? I press the button that says “Book hotel and tickets Now!”. I go to the airport on the designated day. As I walk off the plane into the Honolulu sunshine, I find that my parka is uncomfortably warm.

What happened? The server booked my hotel and tickets, based on the last page I visited - which, as far as it knows, was the Hawaii hotel page. It knows nothing of cloned browser windows and back buttons. When I started asking about Hawaii, it literally forgot about Alaska.

The reason the servers tend to forget in this way is because they only keep one call stack per session. This in turn stems from the fact that HTTP and web browsers were designed for browsing stateless hypertext documents, not for dealing with stateful applications.

Continuations can help here, because they can give us handles for multiple stacks, and allow us to return to different ones at will. This is wonderful, but it’s important to realize that this use case only matters if you’ve designed your UI to follow the he-said/she-said style typical of traditional web apps designed around HTML. This UI is a regression to the days of time sharing, before the advent of the personal computer and GUIs. It’s forced upon you by HTTP; you’d never design a true GUI application to behave this way.

The other important point is that the future of web apps is going to be different. Ajax is a sign of things to come (though it’s only a symptom, not a real solution - but that is another story). In time, entire applications will be downloaded and provide a full GUI in the context of a single page. The primitive dialog we see today will return to the ash heap of history where it belongs.

Such an application would use a modern GUI to open multiple windows on multiple hotels. It would maintain the state that the server “forgot” in our example in objects in the heap. Rather than relying on the server’s stack to keep track of what location we’re looking at, the window showing us the Alaska hotel will be a view on a model object that represents the hotel being viewed. When you pressed “Buy”, it would pass all the information necessary to complete the transaction onto the server. Consequently, we’ll have no more of a pressing need for continuations than traditional applications have today.

Summary: In the short term, continuation based web servers are very nice. Seaside is the nicest one I’ve seen. But ultimately they are just a phase, and we can already see how we will outgrow that phase. Since continuation-based servers won’t be all that significant in the long term, and given the huge lead times and costs of adding continuations to the JVM, it makes little sense to support them.

Comments:

While I could care less about continuation-based web servers, I'd like to see continuations in the JVM as a means to implement a lightweight cooperative threading model. I have an application which has lots of very small cooperative threads, so using java.lang.Thread results in quite a performance hit.

Posted by Jon Nall on May 18, 2006 at 08:46 PM PDT #

what's java?

Posted by Ron on May 18, 2006 at 09:25 PM PDT #

General purpose continuation, as in Scheme, is difficult to implement and even harder to understand. In my 10 years of teaching Scheme, very few student can even write a correct continuation-based co-routine program.
Backward-only continuation, similar to "setbuf/longjump" in C is much easier, but too easy to become buggy and impossible to debug when got it wrong.
I think you should consider the benefit/cost trade-off carefully.
But, if you choose to do it. Go do a world-class job. It is a cool feature.

Posted by Sin-Yaw Wang on May 18, 2006 at 09:26 PM PDT #

Hi,
I don't see the point of having continuations in Java. After all you can always run a good Scheme implementation, with continuations, on top of the JVM.
Cheers,
Antonio

Posted by Antonio on May 19, 2006 at 02:48 AM PDT #

Hi again,
I found this modal web server built with Scheme. Does anybody know of any other implementations out there?
Cheers,
Antonio

Posted by Antonio on May 19, 2006 at 02:53 AM PDT #

"...continuation-based frameworks (Seaside being the quintessential example) are a dead-end. They are a giant workaround for the web..."

http://blog.ianbicking.org/constraints-and-continuations.html

In any case, web issues asside, Lua and IO offer nice examples of coroutines usage:

http://www.lua.org/pil/9.html

http://luajit.luaforge.net/coco.html

http://www.iolanguage.com/about/

http://www.dekorte.com/projects/opensource/libPortableCoroutine/

Posted by PA on May 19, 2006 at 03:54 AM PDT #

In time, entire applications will be downloaded and provide a full GUI in the context of a single page.

you mean, applets from the 90s?

Posted by lee on May 19, 2006 at 05:49 AM PDT #

As been pointed out, there are few decent continuation implementations already. I can even name couple of them in a plain Java and one of them is actively used by Sun and Glassfish community that is working on Java EE components.

Posted by Eugene Kuleshov on May 19, 2006 at 06:02 AM PDT #

Gilad,

I attended your talk yesterday and thoroughly enjoyed it. Thanks. I wanted to ask precisely the question you raise about continuations, but the line seemed a bit long.

The use case you give here for continuations (and therefore the ultimate rejection of consideration for JVM support) seems a bit limited to me. Yes continuations would be very handy for web UIs, but I agree that this model is of probably limited duration. A use case that I think will be of much more lasting interest (and one that is in line with zeitgeist at Sun) is grid computing.

Many uses of grid/utility computing require one to package up discrete computational units and dispatch them out to the grid to be matched with resources and executed. Currently I do that with object serialization, rmi codebase annotation, and all of the machinery of Jini. Basically, I'm handrolling a continuation when I do this and its a very error prone process (lotsa ClassNotFoundExceptions) for which I would appreciate some JVM help. And I don't think this need is going to go away. In fact, I think it will only grow. (Sun certainly hopes it does as a corporation from what I can gather :^) )

The security issues are a real concern, but it seems that Jini has a reasonable handle on those in its model. There are serious EoD issues with that model, but I'm aware of work going on to address some of these, so it's not a pure greenfield kind of development

One final note that will probably obviate any impact of my comments above... I'm with Corky on tail calls. I'd love to see better support for functional languages in the JVM. I think the ability to do this would be major differentiator between the JVM and CLR

Posted by Van Simmons on May 19, 2006 at 07:39 AM PDT #

We have a good way to support multiple simultaneous web conversations in JEE. It's called Stateful Session Beans. When you switch from Alaska to Hawaii, the server needs to know to create a new bean for this second session. For the "how" part, look at Gavin King's Seam stuff.

Posted by Andy Thompson on May 19, 2006 at 08:06 AM PDT #

I don't think it makes sense to bake continuations into the JVM. It is easy enough to come up with a best-fit abstraction for a particular purpose.

Posted by Paul Brown on May 19, 2006 at 12:51 PM PDT #

Oh sure, its just a phase... I've been programming web UIs for close to 10 years, my entire programming career. And the end of 'traditional web apps' is just around the corner, with AJAX as a bell-ringer?

I'll believe it when I see it. I've heard this argument before, you realize... flash, swing applets, ibm's sash, java web-start. Wake me when the revolution has arrived. Until then I'll still be dealing with back-button issues (or buying lots of memory for my continuation based web app) every day. REF: http://en.wikipedia.org/wiki/Betamax to understand that the best technology does not always win.

Zzzzzzzzzz

Also, you don't need continuation support in the language for a continuation-based webserver. Witness Spring Webflow (for better or worse).

Posted by 65.211.178.236 on May 19, 2006 at 02:32 PM PDT #

You list two arguments against supporting continuations in the JVM:

i) continuations are costly to implement,
ii) they might reek havoc with Java SE security model

ad ii) In "A Tail-Recursive Machine with Stack Inspection" John Clements and Mattheias Felleisen shows that the Java security model, which is based on stack inspection, is compatible with global tail call optimization.

http://www.ccs.neu.edu/scheme/pubs/cf-toplas04.pdf

ad i) Costly in terms of what - money? Can't argue about that.

An important use for the JVM is as a backend for other languages than Java. Compilers for Scheme and ML have to jump through all kind of hoops to achieve proper tail recursion with JVM as backend. Adding tail call support would cut execution times in half.

Posted by Jens Axel Søgaard on May 19, 2006 at 05:19 PM PDT #

Antonio, You said: “I don't see the point of having continuations in Java. After all you can always run a good Scheme implementation, with continuations, on top of the JVM.” Yes, but if continuations (or at the very least tail-calls) where in fact implemented in the JVM, the only decent Scheme implementation for the JVM wouldn't be an interpreter, but a compiler.

Posted by ncruces on May 19, 2006 at 07:49 PM PDT #

One has to face the fact that many scripting languages need this to be feature complete. You absolutely need to implement continuations if the JVM is going to support high-performance scripting language implementations like Ruby or Scheme. Without continuations implementers will have to invent their own virtual machines and the jvm as a multi-language host will not succed in the long run.

Posted by morten on May 20, 2006 at 04:20 AM PDT #

I like Python's generators which to me look like "continuations light". Generators are immensely useful for implementing iterators. Would they be a sensible compromise?

Posted by Axel Rauschmayer on May 20, 2006 at 06:14 AM PDT #

You don't want continuations because of web servers. You want continuations because they are a powerful, elegant abstraction: a low-level language component, not a quick fix for one currently fashionable application.

Sure, you can live without them. Just as you can live without classes. But, just as classes are useful because they provide an elegant abstraction that manages state, continuations (or coroutines or maybe generators) provide an elegant abstraction for managing multiple computations.

So the debate shouldn't be "can I think of some end-use that justifies this?" but "what is the best way to provide this abstraction?". If there are costs, what are they, and how do they vary depending on the abstraction used? At what level should they be implemented? What are the security issues (and can capabilities help?)

Posted by andrew cooke on May 20, 2006 at 07:24 AM PDT #

I recently searched far and wide for compelling use cases involving continuations. Despite trying really hard to convince myself that continuations are a critical language feature, I decided otherwise. Here's the list of novel use cases I came up with:
  • Convert an internal iterator to an external iterator.
  • Implement cooperative threading.
  • Use continuations for stateful web servers (as described by Bracha already).

I totally agree with Bracha that the web server use case isn't compelling in the long run. Cooperative threading isn't (IMO) interesting when a language runtime already provides multi-threading. Iterator conversion is a band-aid for dealing with poorly designed APIs.

Note that my list of use cases is specifically for continuations in all their full glory. There are many other uses of continuations, but they do not demand full continuation semantics. There are simpler mechanisms that are subsets of the continuation concept: continuations > {co-routines,lexical closures} > generators

I have come to the opinion that in practice, lexical closures are sufficiently powerful to handle almost all use cases that continuations could be used for, but they are much simpler, both semantically and with regard to implementation complexity.

Posted by Jason Evans on May 20, 2006 at 07:49 AM PDT #

Regarding ncruces comment:
That's a good point! Having continuations within the JVM is good for building compilers. Now, I don't really see why you'd want to build a compiler instead of an interpreter. I like interpreters... ;-)

Regarding Andrew Cooke's:
I agree with Andrew Cooke when he says that continuations are not just for web servers. Continuations are a nice-to-have tool. But, hey, I'm quite happy with the SISC Scheme implementation of top of the JVM. Furthermore, Scheme is a great language.

Regarding Jason's comments:
I'd add error handling to the list of use-cases for continuations. But Java has a sound way to handle errors, aka exceptions, so no full continuation semantics are needed either.
Cheers,
Antonio

Posted by Antonio on May 20, 2006 at 09:54 AM PDT #

I think "wreak havoc" was meant, not "reek havoc", as the verb "reek" signifies the giving off of a foul odour.

Posted by René Ghosh on May 20, 2006 at 01:22 PM PDT #

This attitude toward continuations is exactly why I think Java as a platform is losing mindshare to Ruby, Python, .NET, and others. Sun would do well to pay attention to the innovations that Microsoft is making with their VM. Microsoft is applying functional programming techniques to their platform in a useful way. Java as a platform seems to me stodgy and close-minded to new technologies. I think Sun would do better to find a way to foster innovation and let the community find what works, instead of holding it back.

Posted by cmars on May 20, 2006 at 03:30 PM PDT #

To Van Simmons. It should be possible to avoid serialization and other issues around it. JDO/JPA does it, why can't you? Contact me if you'd like to discuss further.

Posted by Eugene Kuleshov on May 20, 2006 at 07:38 PM PDT #

Antonio, regarding continuations only being useful for compilers... I'd argue continuations (and, even more so, tail-calls) are useful for a hole range of tasks, including building an interpreter - more, I'd argue that's precisely one of the tasks where these features excel. <p/> As to Jason's dismissal of “cooperative threading” vs. “multi-threading”... I'd say some form of cheap concurency (whether cooperative or preemptive) is in order. If I need to scale something to the order of thousands (or, Good forbid, millions) of concurrent “processes”, “hardware threads” sure aren't the answer. <p/> On the other hand, neither Java nor the JVM, need to be “one fits all” tools - but then again, they don't need to be marketed as such either.

Posted by ncruces on May 20, 2006 at 09:22 PM PDT #

Hi ncruces,
Well, I didn't mean continuations were only useful for compilers!! ;-)
Anyway yes, final recursion would be a nice-to-have feature. Indeed. The GCC compiler does (did?) a good job detecting tail recursion and transforming that into iterative alternatives. Anyway as you point out (in the bug description) implementing tail-call recursion would mean removing stack-frames, thus generating security issues. :-(
Now, I wonder if the HotSpot optimization could (does?) detect tail-call recursion and could make (makes?) some room for improvement there. I'll try to do some experiments to validate this.
Cheers,
Antonio

Posted by Antonio on May 21, 2006 at 05:44 AM PDT #

Antonio writes:

> The GCC compiler does (did?) a good job detecting
> tail recursion and transforming that into
> iterative alternatives.

It could do better though:

http://community.schemewiki.org/?gcc-does-no-flow-analysis

Posted by Jens Axel Søgaard on May 21, 2006 at 07:47 AM PDT #

So you are telling us that we do not need a screwdriver in our toolbox because we cannot get those rusty web nails in with it? Brilliant argument! Really: Java is badly designed in many ways. It looks a lot like there was no one around when it was designed who has even the slightest glimpse about language design research of the last twenty years. And it seems that hasn't changed. Given those facts, Java not providing continuations is really a minor point.

Posted by jp on May 21, 2006 at 08:47 AM PDT #

Antonio, about tail-calls (sorry if this is a bit). That tail-calls RFE is not mine, though it has my vote. On the comments an interesting paper is mentioned that defends tail-calls and stack inspection can coexist. Also, tail-calls need not be fully general to be useful - maybe you could optimize them only when all code is on the same protection domain and there are no special permissions granted or revoked (this is also mentioned in some comments).

Posted by ncruces on May 21, 2006 at 10:31 AM PDT #

I don't necessarily disagree with your main point that continuations are an unnecessary feature for the Java language to have. But I can't leave two other items unchallenged: (1) I strongly believe that the Continuation Model seen in things like RIFE or Seaside is the wrong paradigm for solving the multiwindow problem in web applications. A better paradigm is the Nested Conversation Model, as seen in frameworks like Seam or Shale. This model lets you control exactly which UI operations create a new continuable state and which don't, and allows the continuable states to enjoy parent-child relationships. (Sorry, I don't really have space in this comment box to explain the full story here.) (2) AJAX clients simply aren't going to eliminate the need for server-side conversational state. Certain kinds of business logic belongs on the server (eg. stuff that updates databases), and it is most efficient to keep the state close to the functionality - and often also a requirement from a security POV. Eg. I almost certainly don't want to serialize my persistence context to and from the client on every request! Anyway, conversations are useful for more than user-driven applications; they are also critical in the context of ESB. If you look at Seam Remoting, you can see how AJAX and conversations work _together_ :-)

Posted by Gavin King on May 21, 2006 at 08:37 PM PDT #

Here are another three use cases: * Business Process Managment * Workflow * Mobile Agents Any time a developer has an ongoing process that they need to either: * passivate * persist * or move to a different jvm they're forced to come up with some kind of server side state engine to do it. the proliferation of these state engines in the wild is a good indication that the need exists for continuations as a language feature. I'm may be biased because I'm writing a continuations based BPM engine (bpmscript) but it's only because after writing both a mobile agent framework and a general purpose server side state engine, it became clear that continuations are the most natural way to solve this kind of problem. So this is a vote for serializeable continuations support in the JVM.

Posted by Jamie McCrindle on May 22, 2006 at 07:43 AM PDT #

One more time, with formatting:

Here are another three use cases:

  • Business Process Managment
  • Workflow
  • Mobile Agents

Any time a developer has an ongoing process that they need to either:

  • passivate
  • persist
  • or move to a different jvm

they're forced to come up with some kind of server side state engine to do it. the proliferation of these state engines in the wild is a good indication that the need exists for continuations as a language feature.

I may be biased because I'm writing a continuations based BPM engine (bpmscript) but it's only because, after writing both a mobile agent framework and a general purpose server side state engine, it became clear that continuations are the most natural way to solve this kind of problem.

So this is a vote for serializeable continuations support in the JVM.

Posted by Jamie McCrindle on May 22, 2006 at 08:07 AM PDT #

Jamie: How are serialized continuations supposed to interact with synchronized, try/finally, and transactions? I can imagine objects representing continuations <em>of business processes</em>, and libraries or even language features around that. But programmatic continuations a la Scheme? Color me skeptical.

Posted by Jason Orendorff on May 22, 2006 at 02:21 PM PDT #

If I understand the problem correctly, the issue has to do with trying to correctly maintain session state in the browser. If you could maintain rich session state in the client, then the continuation problem goes away. That combined with, as you said, the AJAX model where everything stays on one page, seems like a good solution. One way to accomplish maintaining rich session state on the client is with a client-side cache stored in a local database, ala Java DB. See this blog for more info

Posted by David Van Couvering on May 22, 2006 at 03:29 PM PDT #

Gilad, there are quite lot of uses for continuations beside web applications, Jamie McCrindle already provided a nice synopsis of examples. Here is another very compelling example: writing procedural Java code (as opposed to state-machine like hacks) as handlers for NIO sockets based servers. If you think about it, we still don't have a decent Java HTTP/servlet container that'd operate on NIO, not even leveraging it as far as to handle the HTTP handshake (i.e. the 100 Continue protocol) and request headers. Why? Because it's hard to write it as a state machine. If we had continuations in Java, common code snippets for dealing with HTTP header parsing etc. could be reused in a rather straightforward manner.

Posted by Attila Szegedi on May 24, 2006 at 08:24 AM PDT #

Post a Comment:
Comments are closed for this entry.