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

[redhat-ccm-list] using reified continuations for web page flow control



This is a repost of a message that I posted to an internal mailing list on Apr 
2, 2003.  It has been suggested that this might be of interest to more 
general audience.  I am reposting this with minor changes, mostly of 
orthographical and grammatical nature.

==================


I'd like to give everybody a heads up on an interesting GUI
development method that relies on using continuations for control
flow.

Those of us who went to Martin Fowler's talk at SoftPro in Burlington
in late January may remember the rule of thumb he shared by which he
judges whether you implemented your presentation layer correctly:

  What would it take for you to provide a command-line interface to
  your web application?

If doing so essentially involves writing an entire new front-end from
scratch, then your current presentation layer is coupled too tightly
to your business logic.

The method I will describe in this post seems to have the potential to
sidestep the Martin Fowler dilemma entirely by using the same code for
both the GUI and CLI frontends.

To illustrate, consider the following example of a simple command-line
calculator:

  $ # here's the source code
  $ cat cl-calc.tcl 

  proc calc {} {
      set arg1 [get_num "1st argument"]
      set op [get_op]
      set arg2 [get_num "2nd argument"]

      set result [expr $arg1 $op $arg2]
      puts "= $result"
  }

  proc get_num {prompt} {
      puts -nonewline "${prompt}: "
      return [gets stdin]
  }

  proc get_op {} {
      puts -nonewline "Operation: "
      return [gets stdin]
  }

  fconfigure stdout -buffering none

  while 1 calc

  $ # the script in action:
  $ /usr/bin/tcl cl-calc.tcl 
  1st argument: 3
  Operation: *
  2nd argument: 7
  = 21
  1st argument: ^C

How would you rewrite this application as a desktop GUI app or a web
app?  As a contrived example used for illustration purposes only,
assume you decide to implement it in the simple one-script-per-page
CGI style. The first page asks for the first argument. The second page
asks for the operation and has the first argument as a hidden form
element. The third page asks for the second argument and has the first
argument and the operation as hidden form elements. The fourth page
receives the arguments and the operations, computes the result, and
displays it.

In other words, the informal algorithm for translating CLI apps into
CGI apps is as follows:

 1. Code that is written as a single procedure has to be broken up
    into many separate scripts. In the above example, each line of the
    "calc" procedure translates into its own CGI script.

 2. Most of these scripts need to have machinery for reconstituting
    variables initialized by the previous CGI pages. Contrast this
    with the CLI app where the values of arg1, op, and arg2 are
    immediately available to you, because they are in scope of the
    procedure.  In other words, the web app essentially forces to you
    reconstruct the current stack frame on each request.

If you were the rewrite the CLI calc app as a desktop GUI application,
you'd have to deal with the event loop and event handlers, which
essentially leads to the same difficulties. Instead of having a single
four-line procedure, you have to build a GUI in which user actions
generate events.  You register event handlers, which are callback
functions to which approriate events are dispatched. You have to
maintain the state of your application in a bunch of global variables.
The control flow is now scattered across many procedures that interact
with each other in ways that are not immediately obvious.

Same goes for event-driven, component-based web GUIs like Bebop.


                              A solution

A number of people came independently to a realization that the
problem of web and GUI programming can be simplified if we programmed
in a language that supported continuations[1] as first-class objects.
(Paul Graham[2] has mentioned the use of continuations for flow
control in the Yahoo! Store app that he built with Robert Morris and
Trevor Blackwell in Lisp. Christian Queinnec wrote a couple of early
papers on this subject.  See "The influence of browsers on evaluators
or, continuations to program web servers"[3].  Matthew Fuchs[4] wrote
"Escaping the event loop: an alternative control structure for
multi-threaded GUIs."[5])

If Tcl supported continuations, the above calculator app would work as
a web app like so:

  proc calc {} {
      # the get_num procedure captures the current continuation and
      # sends a page to the user asking for the first argument.  The
      # execution is suspended at this line.
      set arg1 [get_num "1st argument"]

      # When the user submits the form with the first argument, the
      # web server extracts the continuation id that was stored in the
      # form as a hidden field.  The server restores the continuation
      # object and invokes it. The control flow is returned to this
      # procedure at the following line:

      set op [get_op]
      # The above line does a similar thing. The get_op procedures
      # captures the current continuation and asks for the operation.

      # same here
      set arg2 [get_num "2nd argument"]

      # Finally, a continuation is invoked that returns the control
      # flow to this line. Note that we don't have to go through any
      # unnatural motions to extract the values of arg1, op, and arg2.
      # These values are available to us, simply because they are in
      # current scope.
      set result [expr $arg1 $op $arg2]

      # This would have to send the resulting page to the user.
      puts "= $result"
  }


                       Existing implementations

I've seen references to three or four independent implementations of
this idea.  One was done by folks at Northeastern University, the ones
that are involved in PLT Scheme[6]. I don't have a link handy.

Seaside[7] by Avi Bryant.  See him talk about it in [8].  Seaside is
implemented in Smalltalk or, to be more precise, in Squeak[9].

Borges[10] is basically an incomplete port of Seaside to Ruby.

Another implementation is due to Ovidiu Predescu[11] and Christopher
Oliver.  You may have heard about Ovidiu as the author of
xslt-process[12], an XSLT mode for Emacs.  Anyhow, Christopher added
support for continuations in Rhino[13], a JavaScript interpreter
implemented in Java.  I'm not sure if his changes have been merged
with the official Rhino at this writing.  Ovidiu used the
continuations-enabled JavaScript implementation to implement a
control-flow engine for the Apache Cocoon.

Recently[14], Christopher Oliver implemented the PetStore app using
the continuations-based control flow.

I don't know of any reviews of Oliver's PetStore yet. Here's an
interesting recent post[15] to the xml-cocoon-dev list by Pier
Fumagalli:

    Whoever invented the flow, whoever implemented it here, and had
    anything to do with it and brought it to Cocoon is a FUCKING
    GENIUS.

    I shall erect an altar in my fireplace and burn incense to his
    holiness every single day, preaching for my soul to be, at one
    day, of comparable intelligence with his...

        Pier

    PS Can you tell that I started using it? And that it did beat the
    crap out of me? Now I won't be able to design any web application
    without it!


                 Languages that support continuations

Of particular interest to us are implementations that can be used from
within Java. SISC[16] is an extensible Java-based Scheme interpreter
that claims to support the entire R5RS Scheme standard, including full
support for continuations.  This is rather unusual insofar as all
other Java-based Scheme interpreters that I know of only seem to
support escape continuations.

For Perl junkies, here's an interesting post[17] that talks about
coroutines in Perl. Although coroutines are weaker than continuations
(in the sense that the former can be easily implemented in terms of
the latter, but not the other way around), it seems to talk about the
same idea.

To experiment with continuations on a Red Hat Linux box, you can use
guile or ruby, both of which are shipped as part of the standard distro:

  $ rpm -q --qf '%{Description}\n' guile
  GUILE (GNU's Ubiquitous Intelligent Language for Extension) is a
  library implementation of the Scheme programming language, written in
  C. GUILE provides a machine-independent execution platform that can be
  linked in as a library during the building of extensible programs.

  $ rpm -q --qf '%{Description}\n' ruby
  Ruby is the interpreted scripting language for quick and easy
  object-oriented programming. It has many features to process text
  files and to do system management tasks (as in Perl). It is simple,
  straight-forward, and extensible.


References

   1. http://www.cs.indiana.edu/~sabry/papers/continuations.ps
   2. http://www.paulgraham.com/
   3. http://youpou.lip6.fr/queinnec/Papers/webcont.ps.gz
   4. http://www.cs.nyu.edu/phd_students/fuchs/
   5. http://www.cs.nyu.edu/phd_students/fuchs/gui.ps
   6. http://www.plt-scheme.org/
   7. http://www.beta4.com/seaside2/
   8. http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg02456.html
   9. http://www.squeak.org/
  10. http://segment7.net/ruby-code/borges/borges.html
  11. http://www.webweavertech.com/ovidiu/weblog/
  12. http://xslt-process.sourceforge.net/
  13. http://www.mozilla.org/rhino/
  14. http://www.webweavertech.com/ovidiu/weblog/archives/000229.html
  15. http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=104396173510077&w
  16. http://sisc.sourceforge.net/
  17. http://archive.develooper.com/perl-loop perl org/msg00685.html


Additional Reading

  ESOP 2003 Graunke, Findler, Krishnamurthi, Felleisen
  Modeling Web Interactions
  http://www.ccs.neu.edu/scheme/pubs/esop2003-gfkf.ps.gz

  AFP 2002 Felleisen
  Developing Interactive Web Programs
  (Examples in PLT Scheme)

  http://www.ccs.neu.edu/scheme/pubs/afp2002-f.ps.gz


  ICSE 2002 Graunke, Krishnamurthi
  Advanced Control Flows for Flexible Graphical User Interfaces
  http://www.ccs.neu.edu/scheme/pubs/icse2002-gk.ps.gz


  Automated Software Engineering 2001
  Graunke, Findler, Krishnamurthi, Felleisen
  Automatically Restructuring Programs for the Web

  http://www.ccs.neu.edu/scheme/pubs/ase2001-gfkf.ps.gz

  Paul Graunke, Shriram Krishnamurthi, Van der Hoeven and Matthias
  Felleisen.
  "Programming the Web with High-Level Programming Languages".
  Proceedings of ESOP 2001. 2001. Available
  http://www.ccs.neu.edu/scheme/pubs/esop2001-gkvf.ps.gz





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