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

Post/Redirect/Get ( is the relevant design pattern to handle this situation.


9 points by emmett 5952 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, 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 5952 days ago | link

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


5 points by emmett 5952 days ago | link

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


1 point by nostrademons 5952 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 5952 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"
      render :action => "result" if session[:said]

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

  <%= link_to "click here", "" %>
  You said <%= session[:said] %>

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


9 points by brett 5954 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
    def new_fnid(proc)
      @c += 1
      @fnids[@c] = proc
    def query_params(request)
    def pr(response, html)    
      response.start do |head,out|
        head["Content-Type"] = "text/html"
        out << html
    def w_link(response, link_text, &block)
      c = new_fnid(block)
      pr(response, "<a href='?fnid=#{c}'>#{link_text}</a>")
    def aform(response, form_html, &block)
      c = new_fnid(block)
      pr(response, "<form><input type='hidden' name='fnid' value='#{c}'>#{form_html}</form>")
    def process(request, response)
      if (fnid = query_params(request)['fnid'])
        @fnids[fnid.to_i].call(request, response)
        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 :port => 8080 do
    listener {uri "/", :handler =>}
    trap("INT") {stop}


3 points by s3graham 5954 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 5953 days ago | link

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


2 points by saharrison 5953 days ago | link

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


1 point by pc 5950 days ago | link



1 point by simen 5947 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 5954 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 5954 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 5954 days ago | link | parent | on: Table constructor

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


1 point by bogomipz 5954 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)