[EMAIL PROTECTED] wrote: <snip/> > Suppose the application's entry point is the 'startShopping' function, > which is called from the sitemap using the <map:call > function="startShopping"/> entry. Our application displays a list of > items that can be bought as links. When one of the items is clicked, > we want to add it in the shopping cart, and display the list of items > again. We do this until the user clicks on the "Checkout" button > located on the same page. > > The page also displays a little shopping cart icon, which when > clicked, displays the items currently in the cart. > > We'd have something like this then: > > function ShoppingSite() > { > this.cart = new java.util.HashMap(); > } > > function ShoppingSite_chooseItem() > { > while (true) { > // Initialize this by calling the business logic > var itemsToBeDisplayed = ...; > > sendPage("chooseItems.xml", itemsToBeDisplayed); > // Either one item was chosen or a view-cart or checkout happened > var item = cocoon.request.getParameter("item"); > > // If the "item" parameter is present in the request, the user > // chose an item. Otherwise consider one of the other buttons or > // links has been clicked, in which case the "operation" parameter is > // set. The handleOperation() function deals with this. > > if (item != null) { > // We need to add one of the items in the basket. In case the > // item is already there, add one more. > cart.put(item, 1 + cart.get(item)); > } > else > handleOperation(this, k); > } > } > ShoppingSite.prototype.chooseItem = ShoppingSite_chooseItem; > > function ShoppingSite_checkout() > { > // Do the checkout using the "cart" instance variable > } > ShoppingSite.prototype.checkout = ShoppingSite_checkout; > > function ShoppingSite_showCart() > { > sendPage("showCart.html", this.cart); > handleOperation(object); > } > ShoppingSite.prototype.showCart = ShoppingSite_showCart; > > function handleOperation(object) > { > var operation = cocoon.request.getParameter("operation"); > if (operation != null > && operation in object > && object[operation] instanceof Function) > object[operation](); > } > > // The entry point function in the shopping site example > function startShopping() > { > var shopper = new ShoppingSite(); > shopper.chooseItem(); > } > > > The above shows a JavaScript class ShoppingSite which handles all the > various operations usually associated with such an activity. The > startShopping() entry point function in the sitemap creates such an > instance and invokes on it the chooseItem() method. This will loop > forever, waiting either for an item to be selected, or for an > operation to happen. Notice the handleOperation() function which does > this dispatch. To add more operations, you only need to define one > more instance method to the ShoppingSite class. > > Now to answer your question about going back in the history and > choosing a different path. Notice that the 'cart' instance variable > uses a shared Java HashMap instance. This means the same instance is > available to all the continuations, and any modification to it is > visible from the other continuations. This means that if you go back > and modify something in the page #2, the result will affect the cart > in page #12. > > If you want to consider that once the user went back to page #2, s/he > has in the cart only the item he chose in page #1, you'd have to copy, > perhaps in a lazy fashion to avoid memory bloat, the 'cart' instance > variable. This way each page in the tree maintains its own copy of the > cart. <snip/>
Thank you for your clarifying answer! Let, see if I get it right: for traditional webapps like a shopping site you are updating global variables, shoping cart, adress info and so on. For "what if" scenarious you use local variables, and creates the possiblity to "undo" things by creating new stack frames, i.e. by going into a new block or calling a function. IIUC, in the shopping site example above we are in effect only using the application global variable "shopper", the local variables are transient and could be optimized away from the saved continuations with a clever implementation. As a result the continuation objects only need to contain a pointer to the "global" variables and a stack of program counters. The stack of program counters could furthermore be optimized away I belive, in the above example by using tail recursion optimization and by "inline expansion" of some of the functions. In the scenario we also need a mechanism for preventing (or at least warn) the user from reloading the page that excecutes <map:call function="startShopping"/> as this would lead to several independent shopping sessions, which might be highly confusing. Thinking more about the shopping example I think I would like to inverse the control between the sitemap and the flowmap: After all, the "shopping around" part of the story is mainly web-publishing. There is a large database of products that are to be presented, there is a search engine and the access patterns are unstructured rather than linear. All this seem like the tasks where the sitemap excel. Embedded in the pages we might have an overview of the items in the shopping cart, personalized recomendations, links to earlier visited product pages and so on, but this seem still to be information of global character that would easily be presentable with publishing oriented concepts, already implemented in Cocoon. IMO the role for a flowmap is to take care of structured interactions (wizards) and in the shopping case, examples of such are: checking out, editing the shopping cart and uppdating your preferences. So, on a product page there are links like "http://www.foo.com/addToCart.html?prodNo=123456" that call a flowmap function <map:call function="addToCart"/> and "http://www.foo.com/checkOut.html" that call <map:call function=" checkOut"/> and so on. These flowmap functions all works on application global variables, and takes care of structured user interaction. This far in the discussion one might start to get the herretic thought: Ok, handling "what if" scenarious is really cool, but is it worth the effort of saving all the stack frames? Isn't uppdating the old, boring and global session attributes, when thinking about it, a rather good model of what a user might expect to experience from e.g. a shopping site? To conclude: I believe that using continuations is a good idea as it allows us to use control flow concepts from structured programming in our flowmaps: sequence, choice and repetition. The question is: how much should we store in the continuation? If we only use a program pointer we can use basic control flow together with global variables, storing the call stack (a stack of program pointers) we can use (possibly recursive) functions, and by storing all the stack frame, local variables and thus "what if" scenarios become possible. Before having seen some "must have" real world use cases for "what if" scenarios, I tend to think that just storing the call stack would be more than enough in a flowmap language. What do you think? /Daniel Fagerstrom --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]