The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Simple Sequences

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
James Robertson

Posts: 29924
Nickname: jarober61
Registered: Jun, 2003

David Buck, Smalltalker at large
Simple Sequences Posted: May 20, 2004 1:54 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by James Robertson.
Original Post: Simple Sequences
Feed Title: Avi Bryant
Feed URL: http://smallthought.com/avi/?feed=rss2
Feed Description: HREF Considered Harmful
Latest Agile Buzz Posts
Latest Agile Buzz Posts by James Robertson
Latest Posts From Avi Bryant

Advertisement
David Naseby writes
This little exercise has proven to me the value of continuations in writing sequential web apps. This just leaves the question that I haven't yet asked... how useful are sequential web apps? How often does one string together forms in a set sequence? The archetypal example is credit card payment - there is a set series of forms one generally must pass through, from basket checkout to payment process, and Borges'%92 #isolate function comes in handy here. But nothing else springs immediately to mind. Perhaps I'm just too accustomed to bunging too much onto a single form to work around this issue, when I should be thinking more linearly. Or perhaps I've been conditioned into thinking of a more user-driven, event-driven style, rather than an imposed, console-like, application driven process.
David, I'll let you in on a secret: most Seaside apps aren't long sequences of forms. They're event driven, like anything else, and although every once in a while one of those events will trigger a lengthy business process like paying for shopping cart items or booking an airline ticket, for the most part the events are short: show a page of info or a form or two and then back to where you started. Even though, in Seaside, your session could look like a continuous piece of code from start to finish, the truth is that most of that continuum is spent spinning in an event loop, with only brief though frequent forays into sequential logic. It's the same model every UI toolkit uses: user events trigger callbacks which give the application temporary control, but once it's popped up a dialog box or two it falls right back into the event loop.

So why, then, do I blather on about continuations and control flow all the time? Because it turns out that even for those very brief event handlers - even when all they do is show a single page and return - the continuation model is hugely beneficial. Let's take a login link as a simple example. The user is on the home page, they click "login", that triggers an event (in Seaside's case, through a block that's been registered as a callback), and the event shows the login form. Simple enough to do with any old plain-jane web framework, and no continuations in sight - right?

The question is, once the user has succesfully filled in and submitted their credentials, what happens next? Well, next we want to show the home page, since that's where the user was when they clicked login. So can't we just write the login page so that the "submit" event shows the home page if the login was succesful?

Well, hang on. What if this app lets them browse a bit, maybe read but not write, before logging in? There might be a "login" link on every page of the application. So we can't hard code the main page - we're gonna need to tell the login page where it's supposed to go once the user has logged in, so that they get back to the right place. How do we do that?

And, gosh, we do seem to write login pages a lot - what if we wanted to reuse the same one for multiple different apps? Well, we'd probably need to tell it even more, then: not just where to go, but what to do (for this app, do we store the current user in the session? In a cookie? What flags do we need to set based on which user it is?). How do we do that?

It's looking like this simple login page, if we want to reuse it within our application or across several, is going to either become a complex parameterized beast or acquire a couple of dozen nearly identical subclasses. But there's actually a good word for the "where to go and what to do next" parameters that it needs: that's this page's "continuation". And so perhaps it shouldn't be surprising that using a "real", first-class continuation for this simplifies things greatly.

To be concrete: in Seaside, that login page wouldn't have parameters, it would have a return value - some object representing the user or username that had logged in. The login event wouldn't just show the login page, it would "call" it: show it and then wait for, after some further events are triggered on the login page itself, a value to be returned. Only then, and after some processing of the return value, does the login event handler end, at which point the home page (or wherever we started) would be shown again and the event loop continued. So although this was a sequence of only one page, it was a full sequence: to the login page and back again, rather than the GOTO of simply showing a page and stopping there:


login

    |user|

    user := self call: (LoginPage new authenticateAgainst: myAuthDB).

    user

        ifNil: ["login was cancelled"]

        ifNotNil: [self setFlagsForUser: user].

There's a similar example that Paul Graham gives when talking about ViaWeb, which is a color picker. In his store builder, there were many places on many forms where the user needed to pick a color. Rather than ask for a hex value or have a menu of available colors, he had a link that would take them to a full-page color picker; when they had the one they wanted, they'd be returned to the form they started at and the appropriate color value would be set. This is another instance of a page needing to know both "where to go and what to do" - it needs to return to the right form, and it needs to put the chosen color in the right place (were we choosing the foreground text color or the background?). In Seaside, that would again be a simple call and answer:

chooseForegroundColor

    |color|

    color := self call: ColorPicker new.

    myText foregroundColor: color.

Read: Simple Sequences

Topic: Three buttons few and small... One button to rule them all Previous Topic   Next Topic Topic: Announcing XStream: Java to XML serialization, and back again.

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use