Is this a rant? A random thought? A pontification? Well, let's say it's just a personal story (and a concern) I want to share with my fellow Cocooners...
Someone said continuations can be grasped in five minutes, but it may take a lifetime to master them :-)
When first introduced to web programming with continuations I was profoundly impressed to see how continuations "reinvert IoC" and turn event-oriented programming into good ole' sequential programming.
I was even more impressed to see how -with continuations- the infamous back button could become in fact a new, all-powerful tool for what-if scenarios and exploratory browsing.
Boy, is this a triumph of spirit over matter! :-)
After such intellectual orgasm it followed naturally that -from now on- all my EJB-based webapp development *had to* be developed using Cocoon's flowscript.
Unsurprisingly, I was rapidly hit by real-life's nasty habit of impairing golden hammers:
After executing a database-modifying EJB method from the flow, I saw how invoking the same continuation twice resulted in inconsistent database state! Obviously, database modifications reflect all updates made throughout the session, regardless of continuations...
In general, any store will reflect changes made in time. Continuations only preserve _program_ state. Store state has to be accounted for separatedly. Thus, continuations wouldn't spare me from having to keep some sort of explicit dialog control after all...
Since I was playing with a utility "screen" Javascript object (not unlike Chris' [JX]Form wrapper) I was able to easily add a low-level sequence number check to ensure "obsolete" continuations were detected and rejected. Easy hack: it didn't propagate to my application-level flow code.
All of my dialog pages had a "Cancel" button users could click on at any time to abort the current transaction. Checking to see if it was pressed became sort of an "aspect" for every submitted page.
Because pages can be sent ("executed") at any function call nesting level I decided to implement cancellation processing as a Javascript exception that propagates all the way up to the top-level sitemap function dispatcher. Later on, I realized it would be more elegant (and continuation-aware) to create a globally accessible continuation inside the dispatcher and use it as an "escape procedure." Upon invoking such continuation, all other outstanding continuations should be invalidated.
I also "faked" a Javascript component manager which -in absence of the upcoming Cocoon blocks- would provide me with subsitemap-specific components for use in my flow.
By combining form objects, local components and [remote] EJB's, I could keep my flow logic *strictly* flow-related:
... dataModel.dateFormatter = components.dateFormatter; ... welcomeScreen.execute(dataModel); dataModel.requestData = requestDataScreen.execute(dataModel); dataModel.requestAnalysis = requestManagerEJB.analyzeRequest(dataModel.requestData); if (requestAnalysys.evaluation == APPROVED) { confirmationScreen.execute(dataModel); requestManagerEJB.processRequest(dataModel.requestData); } else { sorryScreen.execute(dataModel); }
This was definitively approaching nirvana: flowScript gluing components across application layers. No misplaced business logic, no cluttered "controller" logic, absolute separation of concerns.
But then I realized I had to deal with releasing stateful components...
Sylvain and I have addressed the infamous "automatic component releasing" problem which stems from having to account for continuation trees. His harsh solution (no components leased at continuation creation) seems to be the way to go...
If I'm to follow my intutition -and my own experience- I'd bet many Cocoon developers tend to think in terms of a _single_ outstanding continuation that reflects the webapp's "expected" flow of execution. (It was because of such incomplete mindset, btw, that I first thought acquired components could be automatically released upon sitemap function completion...)
These and similar experiences suggest web programming with continuations is an uncharted, brave new world whose deep ramifications we -mere mortals, non-Lisp gurus- are only beginning to grasp...
Clearly, we need to come up with web-oriented continuation patterns that reflect real-world application constraints. (Does it make sense to "reuse" continuations for form validation? How do we implement one-shot or linear continuations for transactional dialogs with remote servers?)
The core Continuation implementation is superb. The FOM is rapidly approaching a stable form. The next challenge is understanding how to take advantage of this tremendous power while avoiding to shoot our boots.
Just food for thought...
Ricardo