Partial Continuations

A nice introduction by Chris Double.

In the previous example we've effectively called the continuation and then returned back to the caller of that continuation. What we really want to do is capture a 'partial continuation' or 'subcontinuation'. That is, not the entire continuation but a section of it and then return back to the caller.

The 'splitter' operator mentioned in the header to this article implements exactly that. It marks the point at which a continuation should be captured up to, instead of the entire continuation. A 'partial continuation' can then be reified up to this point.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Okay, but why?

It's a nice trick, but I don't understand why anyone wants to use a continuation for this in the first place. A continuation looks to me like a particularly obscure way to represent a web session, and web sessions are something I try to avoid in the first place. A well-designed web site should avoid having per-user state saved on the server. That is, the state should be encoded, in order of preference, in the URL, as hidden fields in a form, as cookies, in a database, and only as a last resort in a web session. And if the data's in the web session (such as a shopping cart), it seems far more straightforward to represent it as a shopping cart object rather than as a continuation.

As a matter of curiosity

Why is storing state in a database better than storing it in a web session (presumably you mean in persistent memory on the server?) I can see how it might matter if a) you have several servers, behind a load balancer, and b) the same client cannot be guaranteed to connect to the same server for every request. In the event of a), is the guarantee missing in b) really difficult to provide?

I would suggest that wherever and however session state is stored, it's still session information. The continuation-based approach makes explicit the connection between this stored session state and flow of execution - a continuation isn't likely to be mistaken for any other sort of persistent data. I've never tried to build an application using this approach, but I can see that it might have its merits...

It's for failover

I don't like the idea of relying on sticky sessions (where requests from a user always go to the same front-end server) because it doesn't handle the case when a front-end server crashes, in which case (b) is impossible. Better to write code that's correct regardless of whether sticky sessions are in use or not. (They can be a performance win due to caching.)

serializable continuations work here

You can still store session information using continuations and have failover. If the continuation is serializable then it can be stored in a database. It can be loaded on any server (not just the original server that captured it) and resumed.

Flexibility

It depends on what you store in the session.

The main problem with all sessions is that a) the user may press reload, b) the user may use the 'back' button and c) the user may open new windows, thus fork the session.

I can imagine that there are ways to handle these situations with continuations, but they are far more complicated and less intuitive to me than by storing them in a format that does not have such a tight relation to the code/implementation.

(in general it's best to store only authentication information in a session, and as much as possible in the forms)

Continuations make this easier

Continuations actually make reloading, the 'back' button and forking easier. Since each URL is a reference to the continuation, reloading is simply re-running the computation from that point again. ie. resuming the continuation. Ditto with the back button. You get that functionlality for free. Forking is the same. At any point you can go back to a prior continuation and resume it, with the state captured in the continuation correctly backtraced. Any state stored in the database (or other persistent store) won't be backtracked so you are able to pick and choose what you want to be backtracked and what you don't. It all comes for free. Well, almost.

From the number of J2EE based web application frameworks (Echo for example) that don't handle the back button very well it would appear to be a difficult problem and using continuations helps here.

ignore session handling

IIUC the point of continuation based web framework (borges for ruby, Seaside2 for squeak and UncommonWeb in CL) is to relieve the developer of the need to handle the session data by itself. It is not a matter os storing session data in a url, is a matter of automagically find yourself in the middle of the computation withouth having to check the session information ate every point.

The usual example from Avi Bryant is that common web frameworks resemble the explicit usage of GOTOs to handle control flow, while using Seaside you're actually programming in a structured way.

Maybe this can be of interest to you (mainly the third entry)

Also...

Implementations differ. Some actually encode the continuation and send it to the client (as a hidden form element, or a cookie). Some store the continuation in a hashtable or database, and have the client return a key. Continuations can be serialized, persisted, retrieved and deserialized. They don't have to live permanently inside the memory allocated to a server process (or shared between multiple processes).

What about versioning?

It seems like a persistent continuation would have to be very dependent on the exact version of both your application and the language it's written in - you've got all this implementation-dependent stack-frame stuff in your data format. When you deploy version 2 of your code, how do you upgrade all your persistent version 1 continuations? An explicit data format has the advantage that you know when you're breaking backward compatibility and can provide some kind of migration.

Serialization in Java at least provides some hooks for migration, but it's still implicit enough that people often forget that they have to handle migration when changing a field.

Usually the continuation data

Usually the continuation data in a continuation based web server is not long lived and tends to expire in a reasonably short time anyway. When upgrading, it is often the case that all the continuations are manually expired forcing a reload. When upgrading the application in areas where data needs to be long lived, I would not store that session data in the continuation but elsewhere (like the database).

Continuations sent to the client

Some actually encode the continuation and send it to the client

That sounds like the right way to do it. I've never heard of that before. Which implementations do this?

It has pros and cons like everything...

I believe the paper "Automatically Restructuring Programs for the Web" discusses this approach (http://www.ccs.neu.edu/scheme/pubs/ase2001-gfkf.pdf),

The problems you face with this approach are:

1) The size of the continuation can make the data transferred to the client reasonably large.
2) The data needs to be encrypted to prevent the client from manipulating it. This can have performance/size impacts as well.
3) Bookmarking is problematic.

The average size of a serialized continuation in the Scheme server I work on is about 40Kb. This is uncompressed. It gzips to about 12Kb with not much noticeable speed degradation on resuming it. So it would certainly be possible to store in a hidden field on the client.

Another disadvantage would be the difficulty in 'bookmarking' a page. By giving each page a unique URL identifying the continuation it allows the user to bookmark it and resume computation from that point at any time. This can be quite a useful feature. It allows Haystack style 'User interface continuations' where you partially fill in a form with common information, fork the window or bookmark it, and continue from that point numerous times to fill in the non-common information.

The big win is not having to store state on the server making things quite a bit simpler in that regard.

Bookmarking vs. saving

Bookmarking is problematic.

If you think of a URL as a variable, and a page served for the URL as the variable's value, then the web is an imperative (and concurrent) language, since the page associated with a URL can be updated. In such a language, you need to distinguish between computations which depend on variables and ones which depend on values.

Bookmarking lets depend on a URL; to depend on the value, you have to save the page. In this case, I think saving the page is more appropriate, don't you?

The approach of storing state in the URL is a bit like writing imperative code in a pure functional language; you emulate an updateable variable with a sequence of functional variables. But it seems this is doomed to failure, anyway, since the page associated with a URL is bound to change sometime, for example if the site moves or is abandoned.

So in the end the only way to be sure is to save the page.

Just to be pedantic

the page associated with a URL is bound to change sometime, for example if the site moves or is abandoned.

True.
Though, unlike a variable,
the URN will be globally unique forever, and may well be used as a reference to a resource well beyond the lifetime of the resource it identifies or of any naming authority involved in the assignment of its name, URLs do not have such semantics.
A URL identifies the location or a container for an instance of a resource identified by a URN. The resource identified by a URN may reside in one or more locations at any given time, may move, or may not be available at all.

For example, ftp://ds.internic.net/internet-drafts/draft-ietf-uri-irl-fun-req-02.txt does not work anymore (it used to be a URL for "Functional Requirements for Internet Resource Locators").

So URNs are like values, while URLs are like variables.

[on edit: URNs are not the values refered by URLs. They are, eh, names resolved to variables (URLs) given the scope. This language looks to have a dynamic scoping...]

The Tube

As part of his PhD thesis on "The Tube", David Alan Halls explored stateless servers, where continuation data is stored as a hidden field in the forms sent to a web client.

haskell wash

Does Wash (Haskell) count as a continuation based web framework? The updowncounter example given in the wash documentation looks similar to an example given in the seaside documentation.

For web applications rather than web sites

Continuation based web systems tend to be used more for web applications rather than web sites. Things where the control flow can be more complicated than usual. The ability to write the code so that it is in a natural imperative style can be a win for these cases. The data stored in the continuation is usually 'transient' or temporary and eventually gets committed to the database or persistent storage. It should be data that is not critical if it is lost, expired, or otherwise discarded (ie. the user can restart the session if needed).