Writing dynamic webpages with continuations can save a lot of pain, by letting the computer compile the inversion of control away. Unfortunately, continuations can rarely be exported outside the language implementation's runtime, so we are usually forced to save them at the server, and only pass a handle to the client. Not only may this open the server up to DOS attacks, but it also usually means that URLs have a finite, and relatively short, lifetime.
Common Cold (CC)'s continuations are serialisable,
avoiding these problems and much of the complexity associated with
them. Moreover, instead of attempting to 'hide' the fact that we do
not use native continuations, I tried to make the transformation as
explicit as possible (by having the package use its own special forms
instead of a codewalker), but still usable (by using its
CC supports both lexical bindings (static scoping) and special variables (dynamic scoping). Serialised closures or continuations always create fresh copies of the lexical scopes in the state they were when the closure or the continuation frame was created. Assigning to lexically bound variables can result in surprising behaviour, especially since closures/continuations that have not been deserialised have normal CL lexical bindings. Again, in the interest of explicitness, nothing is done to prevent this from happening; the programmer may very well know that a given variable is only assigned to before capturing its scope. Note that side-effecting lexically bound variables in continuations-based web framework is often a cause of weird bugs, since it can be difficult to know when bindings must be shared, and when they must be copied. Special variables are the prime way to introduce mutable bindings in CC. Specials created in CL code or via CC's own special forms can be mixed transparently, but only CC's special forms will capture them in continuations. Dynamic bindings are never shared between continuations, and are recaptured every time a continuation is captured. Assignments to special variables are thus carried from a continuation's invocation to the next.
Specials are also treated specially by the web
serving code. While the bindings are always saved in the
continuations, the topmost (non shadowed) ones are also exposed as CGI
parameters (as their qualified, URL-encoded,
to the continuation's URL (this part may be buggy
GET forms?). When a continuation is invoked (a
response is sent to the server), the topmost special bindings are
replaced (as if by assignment) by the rightmost parameter with the
corresponding name, if any. Parameters can thus simply be special
variables (I should create a special package for them to avoid their
being qualified), which will be side-effected with their value in the
form if any. Since CC uses Hunchentoot, it is of course also possible
to use Hunchentoot's functions for better access to parameters or
control of the headers.
Lexical bindings may be created
the computed values may capture the continuations;
let* are fine). Local
functions should be bound normally, using
labels. Special variables may be introduced
(if no continuation will be captured in their dynamic scope, normal
CL special forms will also work). Finally,
introduces sequencing (when one of the forms may capture its
catch frame (that
interacts with CL's
correctly, but is captured in continuations),
mreturn (which may not always interact correctly
Page creating functions simply return a string,
and may use Hunchentoot's functions freely. To use
send/suspend may be
[argument-function]) unwinds the stack (thus making it
closer to shift), builds a copy of the continuation's dynamic scope
environment, and calls its argument function, passing it the URL
representing its continuation. The argument function should return a
string, the web page's contents.
[body]) builds on top
[k] bound to the URL
send/suspend's continuation. The body
should evaluate to the response page's contents. In both cases, only
a copy of the dynamic bindings is restored. Side effects, even to
special variables, will not be reflected in the captured
etc. are not active.
The continuation part of URLs are encrypted using AES
when a secret key has been registered
register-key. Registering a zero-length key
disables the encryption (which is disabled by default). Continuations
are then base64 (adapted to URIs) encodings of unencrypted gziped
ensure-all-builders may be called at any time to
compile all fragment (closures or continuation frames) deserialising
functions. In would then be possible to export the data to other nodes
for easier load balancing.
make-continuation-handler should be
used to create a dispatch function for Hunchentoot. The example should
make its usage clear.
The user should mostly be interested in
sfunction, special forms that are, respectively,
function, but return
closures that can be serialised (printed readably).
Exports symbols related to dynamic-binding and catch frames, and
the macros for the continuations mini
invoke-cont may be interesting to someone
building something else.
Fills the COMMON-COLD package, which is the only one that should
be USEd by the user. Defines
the web interaction-related functions/macros, and all the
continuation encoding machinery.