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

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 6122 days ago | link

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

-----

9 points by emmett 6125 days ago | link | parent | on: Take the Arc Challenge

One thing I've noticed about languages: you can't really tell which is better from such a short sample.

Paul calls Prolog pattern matching great for writing basic list manipulation functions, then downhill from there. But if you're looking at those kinds of toy problems (how do you write reduce?) you get a biased sample.

Really, you have to try writing something representative of your problem space. And that code snippet is not at all representative of my experience writing web applications; it lacks:

  * Persistent storage
  * Large pages with multiple possible forms and actions
  * Javascript
  * Caching
  * Complicated queries
  * Pagination
In fact, what the demo code amounts to is a 2 step wizard. And in all of Justin.tv, we only have two wizards. So I don't think this is a good test for length of a web app.

One extremely important question: What would be? Is there some kind of canonical example application that could be designed?

-----

5 points by nostrademons 6125 days ago | link

Reddit clone, including AJAX voting & comments and different sort orders.

-----

5 points by emmett 6125 days ago | link

Wait a second...I think we might already have this written in Arc...

-----

1 point by nostrademons 6125 days ago | link

I think we might already have it written in several languages...

So let's have the Reddit-clone challenge!

-----

3 points by vikram 6125 days ago | link

A wiki

-----


Typically, you'd never write the program that way in Ruby. All the popular ruby web frameworks are not continuation or closure based. Instead, you'd keep the state in memory on the server, tied to the session. You'd also use three templates, one per page. In Rails:

  def said
    if request.method == :post
      session[:said] = params[:said]
      render :action => "clickhere"
    else
      render :action => "result" if session[:said]
    end
  end

  default template said.rhtml:
  <% form_tag do %><%= text_field_tag "said", "" %><%= submit_tag %><% end %>

  clickhere.rhtml:
  <%= link_to "click here", "" %>
  
  result.rhtml:
  You said <%= session[:said] %>

But now that you mention it, ruby has callcc...let me see what that implies...

-----

9 points by brett 6127 days ago | link

you don't really need callcc as much as just storing proc closures

here's a ruby version a bit closer to the original. there's a bunch of support and then process roughly corresponds to said above

  #!/usr/bin/env ruby
  require 'rubygems'
  require 'mongrel'

  class FooHandler < Mongrel::HttpHandler
  
    def initialize
      @fnids = {}
      @c = 0
    end
  
    def new_fnid(proc)
      @c += 1
      @fnids[@c] = proc
      @c
    end
  
    def query_params(request)
      request.class.query_parse(request.params['QUERY_STRING'])
    end
  
    def pr(response, html)    
      response.start do |head,out|
        head["Content-Type"] = "text/html"
        out << html
      end
    end
  
    def w_link(response, link_text, &block)
      c = new_fnid(block)
      pr(response, "<a href='?fnid=#{c}'>#{link_text}</a>")
    end
  
    def aform(response, form_html, &block)
      c = new_fnid(block)
      pr(response, "<form><input type='hidden' name='fnid' value='#{c}'>#{form_html}</form>")
    end
  
    def process(request, response)
      if (fnid = query_params(request)['fnid'])
        @fnids[fnid.to_i].call(request, response)
      else
        aform(response, "<input name='foo'><input type='submit'>") do |req1, resp1|
          w_link(resp1, "click here") do |req2, resp2|
            pr(resp2, "you said: " + query_params(req1)['foo'])
          end
        end
      end
    end
  end

  Mongrel::Configurator.new :port => 8080 do
    listener {uri "/", :handler => FooHandler.new}
    trap("INT") {stop}
    run
  end.join

-----

3 points by s3graham 6127 days ago | link

Neat, thanks. (Not quite "right" since I can change &foo=myinput on page 2, but I'm guessing that could easily be fixed with an extra closure somewhere).

-----

3 points by lojic 6126 days ago | link

You can use request.post? instead of request.method == :post if you like.

-----

2 points by saharrison 6126 days ago | link

Ruby's callcc is not a true continuation -- you can't store the state of the continuation.

-----

1 point by pc 6123 days ago | link

Huh?

-----

1 point by simen 6120 days ago | link

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

-----


Ruby, in 1.8, has arc-style strings: "foo"[0] == 102

In 1.9, it's moving towards Python: "foo"[0] == "f"

This is extremely sensible. I have never wanted the character code of an arbitrary index in a string. I always want a single character substring.

-----

2 points by scav 6127 days ago | link

And in 3.0, Python is adding a bytes type, so b"foo"[0]==102

Obviously both ways are useful. If I had to guess what Arc ends up doing, I'd guess : whatever leads to the programmer having to type less tokens, or whatever facilitates clever macro definitions, leading to same.

-----

5 points by randallsquared 6127 days ago | link

I would suggest that marking a literal vector of bytes is not the most useful role double quotes could play. Python has a lot of history of using that, due to exactly this kind of confusion of strings and vectors of bytes, leading to b"", u"", etc.

-----

1 point by emmett 6128 days ago | link | parent | on: Table constructor

(obj x 1 y 2) isn't close enough?

-----

1 point by bogomipz 6127 days ago | link

obj is a macro, which means it can't be used with higher order functions. Also, what if my keys are held in variables? I can't write this with obj:

  (table name-key name age-key age)

-----