Arc Forumnew | comments | leaders | submit | pc's commentslogin

Huh?

-----

1 point by simen 6166 days ago | link

Ruby's continuations can't be serialized. That does not make them any less true continuations, though.

-----


Most of the examples posted so far fail in a fairly big way -- they break if you use the "said" page in more than one tab. Pretty much all of the examples that use cookies have this problem.

This might seem like a minor thing, but it ends up being pretty important in practice. E.g. most airline fare comparison sites don't allow you to do multiple searches in parallel; most checkout processes get very unhappy if you use the back button. The basic browsing metaphor -- of a page's state being contained within that page -- is broken by cookies, and it shows even in these toy examples.

(Sometimes breaking that metaphor is ok -- e.g. for persistent logins.)

With the closure-based approach, you don't have to worry about tabs, or the back button, or any other issues caused by badly leaking abstractions.

http://www.google.com/search?hl=en&q=%22don%27t+use+the+..., http://www.google.com/search?hl=en&q=%22don%27t+click+th...

-----

6 points by kens 6170 days ago | link

I think cookies vs closures is mixing apples and oranges. First, if you're using server-side state, the session ID can be stored in a hidden field (post) or URL (get) as Arc does, or the session ID can be stored in a cookie. The cookie behavior can be a bug or a feature depending on what you're doing; for example, you probably don't want two different tabs to have two different shopping carts and two sets of user information. Session ID in the URL has the disadvantages of ugly URLs ("sessionid=line noise"), lack of persistence, difficulty with bookmarking, and SEO negatives. Web frameworks (JSP, ASP) typically support either model.

Second, improving back button behavior is a matter of setting all the right nocache attributes. If you use forms, you're likely to have trouble with back navigation no matter what you do ("The page contains expired POST data").

Finally, I don't see how closures have any impact on the user experience one way or another, since it's just a different way of storing server-side state. The server can be implemented with closures, in-memory state, state backed by a database, or trained pigeons and it shouldn't make any difference to the user. (Modulo performance, reliability, etc of course.)

Am I missing something about how closures solve tabs and all other leaky abstraction issues?

-----

4 points by pc 6169 days ago | link

"I think cookies vs closures is mixing apples and oranges"

In theory, that's absolutely true; of course there's no technical reason that one can't use cookies and still keep the desirable properties of the Arc example (outlined in the grandparent).

But that's really the point: even though both styles make either model _possible_, they still encourage radically different approaches -- and this is of course borne out by the stuff people have submitted.

Secondly, on the perceived cookies/closures dichotomy, you reduce things to a question of where one should store the session ID, and that's a totally orthogonal issue.

We basically have three models -- sessions with IDs in cookies, sessions with IDs in URLs, and closures. Cookies give you a single, linear progression of state; session-IDs-in-URLs give you multiple linear progressions; and closures give you a nonlinear tree of progressions.

What do I mean here?

Sessions with IDs in cookies are simple: they're a single global state. Session IDs in the URL are a small bit closer to the closure-based approach, but they really just mean that the flow of state proceeds linearly in several independent threads. It's still a long way from matching the browser metaphor of "a page's state being contained within that page".

With session IDs in the URL, you can't get identical semantics to the closure-based approach unless you do make your sessions immutable, and create a new clone at each juncture. And if you do adopt this "session frame" approach (should that be "stack frame" approach?) you've basically created succumbed to some form of Greenspun's Tenth Rule.

Does this really matter? When state is contained within the page -- that is to say, when the closure-based approach is used -- it makes for much more flexible browsing. To take a tangible example, say you're searching for an airfare. You first search for tickets from SFO to BOS, then on the next page pick dates, and then on the third you (holding down alt) open a new tab investigating the price when you book first-class, while you proceed with economy in your main tab. You go through a few more pages, and you're now at the checkout in both. But you realise that you really need to go a day earlier, and that first-class is too expensive, so you close that tab, and hit back 'till your at the date selection page, and then head back to the checkout.

And it all just works. We humans are inquisitive creatures, and the tree of closures facilitates our natural instinct to poke and then retreat when things don't look right. Desktop app designers have long known this (even the first Macintosh had undo), and though generally far less information-dense, almost any modern desktop app supports virtually-infinite undo. Session-based approaches on the web choke this.

If the airline example sounds a bit contrived, it's because it is -- but at the same time, it's also a lot less chaotic than many people's flows when going through this an airline booking process (I know that for a fact because I spent a while investigating it once...).

The biggest difference between my example and real life is that, in mine, things _work_, whereas in real life, opening the new tab or using the back button would almost certainly completely screw the web-app up.

As heavy internet users, we've grown to accept this crap, because 1) we're used to it and 2) we know it's hard to get right. But it's not inevitable. Browsers can still be made to work as advertised.

This response has been hurried; I should probably make it into properly-written blog post or something.

-----

3 points by olavk 6168 days ago | link

Another option is to have all necessary information about the current operation in the URL. This is highly scalable, since you don't need to keep track of anything user-specific on the server(s), and the navigation supports branching and back/undo just like you describe.

Strangely enough PG specifically disallow this approach in his competition!

Most web apps need _both_ global session state and URL-based state. As others have pointed out, if you browse a product catalog, you would like to be able to branch into different browser windows or use the back-button. However, when you add an item to the shopping basket, you want it to be a global state change (you want have the same shopping basket in all windows), and you don't want a buy to be undone by clicking back.

Continuations are only an options for handling URL-based state, not for handling global state. And for page state they have some limitations.

For example, if all navigation is handled by continuations, you basically have to store a continuation for every hit indefinitely, since you dont know if the user have bookmarked the URL. If you don't want to store the continuations forever, you should only use them on pages that are not bookmarkable anyway, i.e. pages that are the response to form posts. But then the stated advantages, like the ability to branch and use the back button is moot, since you cannot do that anyway with form responses.

Continuations are really nifty for quick prototypes of web apps, but for production use, I believe they are a leaky abstraction.

-----

1 point by pc 6149 days ago | link

"Continuations are only an options for handling URL-based state"

This isn't true.

-----

6 points by emmett 6170 days ago | link

I think you're spot on. I just wanted to share a little trick, with regards to:

  Second, improving back button behavior is a matter of 
  setting all the right nocache attributes. If you use forms, 
  you're likely to have trouble with back navigation no matter 
  what you do ("The page contains expired POST data").
The key is to use a 302 redirect immediately after a successful post rather than a 200. This makes using the back button take you back to the form, rather than trying to POST it again.

On the other hand, I find the ability to resubmit forms with the back button very useful at times, so I'm not sure this is always the right thing to do. But it's a neat trick.

-----

1 point by JoshKingBoston 6169 days ago | link

Post/Redirect/Get (http://en.wikipedia.org/wiki/Post/Redirect/Get) is the relevant design pattern to handle this situation.

-----


  | foo |
  foo
    ifNil: [html form: [html textInput callback: [:t | foo := t]]]
    ifNotNil: [html anchor callback: [self inform: 'You said ', foo]; with: 'click here']

-----

4 points by ben 6171 days ago | link

In case anybody is wondering, this is smalltalk and Seaside.

-----

1 point by cwp 6171 days ago | link

Nice idea, but it doesn't work. It should be something like this:

    renderContentOn: html
        said 
            ifNil: 
                [html form: [html textInput callback: [:v | said := v]. 
                html submitButton]]
            ifNotNil:
                [clicked 
                    ifNil: [html anchor callback: [clicked := true]; with: 'click here']
                    ifNotNil: [html text: 'You said: ', said]].
A more elegant implementation might use the lower levels of Seaside directly, and dispense with components completely. But Arc is about brevity, not elegance, right?

-----

2 points by pc 6171 days ago | link

Well, even that code omits the definition of "said" and "clicked". (The latter is unnecessary as far as I can see.)

I agree that mine isn't precisely by the spec -- you have to press 'enter' to submit the form, and there's an ok button on the last page -- but these are fairly trivial differences in presentation due to the behaviour of the built-in libraries.

(also, minor footnote: I'm assuming that "foo", "said" and "clicked" are instance variables in each example.)

-----

2 points by pc 6175 days ago | link | parent | on: Arc as a better "common" Lisp?

The lack of closures just means the compiler has to do a little more work.

-----