Re: Continuation based app servers



Dustin Withers <fadeddata@xxxxxxxxx> writes:

Is there a reason for this? Is UnCommon Web a secret weapon? Or only
used by Marco? ;)
I think one of the reasons may be that UnCommon Web is the only Lisp
framework that people know of :)

[SHAMELESS PLUG]
A little over one month ago I left my job. I have spent a huge chunk
of my time writing a web framework in Common Lisp. In retrospect, not
looking at UnCommon Web was a NIH syndrome but I've accomplished so
much in this time that the thought of throwing it away gives me
chills. I hope to release the framework in the coming months. You can
see some screenshots here:

http://www.defmacro.org/temp/shot1.png
http://www.defmacro.org/temp/shot2.png

This is my first major Common Lisp project and I can say without any
reservations - the benefits I've reaped blow every other language
known to me out of the water (and I know quite a few). I have a few
widgets I have to finish, at which point I'll arrive at one of the
crucial milestones - designing modal interaction.

I've left a few doors open to take the framework into one of many
possible directions in this respect. As I think about this more and
more I keep coming to the conclusion that it's best to limit the
framework to support modal development without continuations.
[/SHAMELESS PLUG]

Here is what I want to support:

(defun authenticatedp ()
(if *authenticatedp*
t
(do-modal #'login-or-register)))

(defun some-action ()
(when (authenticatedp)
(do-action)))

The key is 'do-modal' - a construct that shows a login page (which can
manage rounds of user interaction), and returns the result of the
login operation as if it were a simple function call.

I don't need continuations to achieve this functionality. The trick,
saving the stack, can be done with threads. Whenever 'do-modal' is
called, it can spawn a thread and assign it to the current
session. All interaction will then be executed by that thread while
'do-modal' blocks the original thread and waits for some signal from
the new one.

Naturally it's necessary to map a session to the current thread and
take care of the back button. This seems rather simple - assign a
number to each request and whenever 'do-modal' is called, store the
number in some data structure. If the user hits the back button enough
times that he leaves the "modal" part of the page, the framework can
detect that and simply signal the waiting threads to resume. I don't
need support for restartable computations to support the back
button. For instance, if the user hits pages A, B, C, D, then hits the
back button twice and executes some action from B, pages C and D are
gone forever (which will be simulated by unwinding of the stack via
unblocking threads).

The only time continuations *may* be useful is when the user clones
the session in another browser, but that's a very moot point. First,
cloning isn't generally an expectation since you can only easily clone
a session when cookies aren't supported and the session ID is
rewritten on the URI. Second, even if you do take that path,
continuations that maintain UI state will gradually grow out of sync
with the backend data you modify through PUT requests. The user will
end up seeing a UI for a non-existant back-end state - IMO a very
undesirable situation.

As far as I can tell the common "integer counter" example is very
contrived. You have a state zero, you proceed to click "increment"
four times, then hit the back button twice, hit "increment", and
expect to see a three, not a five. Assuming this is desireable (you
wouldn't want stuff disappearing from the shopping cart), you've now
introduced a problem similar to cloning - the data in the database
you've commited with PUT requests is out of sync with your widget
state. I'm not sure how one would handle such issues in practice, but
if you really want to you don't need continuations to do this either -
simply store user actions in idempotent closures (set to value,
instead of toggle).

Disclaimer: my ideas about modal web application programming are
untested. I will soon implement everything discussed above and report
back my findings.

--
Regards,
Slava Akhmechet.
.