[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Continuations

On Tue, 12 Aug 2003, Michael Sperber wrote:

> Right.  Applied to this scenario, I realized that the distinction *is*
> important when it comes to Web programming:
> "State" is something about the world.  Let's say it's something like
> the balance on my online account.  I change it by pressing buttons
> labelled something like "Buy NOW!" or something.  These things don't
> get revoked when I press the Back button on my browser.  Thus, a
> (possibly persistent) store is the right medium for carrying this kind
> of stuff, and mutation is the right operation.
> On the other hand, where I am within a session isn't state because
> it's not about the world---it's about what browser window I'm looking
> at.  This is about binding because it's about the context I happen to
> be operating from, and mutation is the wrong operation:  I don't want
> what I do in this window to affect other windows.  Thus, conflating
> the two notions (whether in terminology or some hodgepodge "session
> state object") is a bad idea.

Exactly right.
Unfortunately, in many languages, the most natural way to model what's
going on in the browser window (and this is more than just "what browser
window I'm looking at"; it's also which nodes are expanded in a tree
widget, say, or which tab of a tab panel is selected, or what temporary
choices have been made in a form), is with mutable state.  So you have to
disntinguish between what I call the "domain model" state and the "UI
model" state.  Only the latter state should be captured and rolled back
when the user hits the back button.

In Seaside, both kinds of state are represented by Smalltalk objects.
Any mutable objects that belong to the UI model have to be registered with
the session.  When it captures a continuation, it also snapshots the state
of any of these registered objects.  The continuation gets wrapped in a
closure that hangs onto this snapshot, and restores those objects to their
former state before invoking the continuation.

I've gotten more careful over time about how I use this facility.  At
first I registered pretty much any object having to do with the UI.  Now,
I tend to selectively box individual pieces of state and register only
those boxes (ValueHolders, in Smalltalk terms - you'd use a single-element
array in Java), effectively making them mutable, backtrackable bindings.
In Scheme I can imagine introducing something like backtrackable-let.