Brian's Waste of Time

Mon, 04 Oct 2004

Darn you, Leo =)

Leo Simons challenged me again =) Okay, thinking about it some. No code but...

You don't really need continuations for linear web programming. They are the best existing way of representing the idea though. You need something to track the state, and something to get compiled (or interpreted and have state stored) representing the state machine. Ruby doesn't have macros (tons of fun stories there) but method_missing, mixins, and singletons (not GoF singletons) allow for very similar domain specific structures.

The problem, I tend to think a little non-linearly, sorry for jumps, being addressed is linear programming for web apps in ruby. Rails rocks, but it is another action based system. Ruby supports first class continuations. They are, however, bound to the (ruby) thread from which they were generated. This is a bit tricky for web applications. I don't know for sure how Borges deals with it, but from playing with Borges... I am going to guess "not well" is the answer.

Okay, so we need to either use a single-thread model, be able to re-attach a request to the thread that the session is associated with... hmm, I wonder if continuations span fork in ruby, anyway... or fake out continuations by managing a seperate binding stack (convenient as, while the performance is less than ideal) you can treat a scope binding as a first class object in ruby.

More brain dumping, need some music... okay. So we need to simulate the behavior. It is acceptable to require explicit binding of state which traverses responses to something (we'll call this a wombat for lack of good name and not wanting to interrupt thoughts), that is reasonable. It beats state machines (wheee), even if it is a touch unnatural. So you have something like:

class BlogPoster < Wombat

  include RepositoryHelper

  def create_entry
    title, body = get_title_and_body until title and body
    
    category = case body
      when /[Jj]ava/, /argumentative/ then "java"
      when /[Gg]roovy/ then "groovy"
      when /[Rr]uby/ then "ruby"
      else "misc"
    end
      
    begin
      entry = repo.createEntry(category, title, body)
    rescue
      send_page "data_error"
    end
    
    send_page "home"   
  end

  # returns request params specified
  def get_title_and_body
    self.get_response("entry_input", [:title, :body])
  end

end

Hmm, looking at that and no go. Need to keep stack information, pointer to execution, etc. Continuation. Okay, so we know we need continuations, and we know continuations are bound to the ruby thread that spawned them. get_response specifically needs to do a callcc to something which will hold the continuation and come back on next call from client.

Okay, diving into Borges to see how they handle multithreading... argh am supposed to be hacking other things...

3 writebacks [/src/ruby] permanent link