Bill Clementson's Blog

Bits and pieces (mostly Lisp-related) that I collect from the ether.

August 2005
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Jul  Sep

All Your Closures Are Belong To Us

Wednesday, August 3, 2005

I was originally going to call this weblog entry "Developing Continuation-Based Web Applications with UCW" but that sounded way too boring!

I really liked the UCW introduction tutorial movie that Marco Baringer did the other day. Introductory material is important to draw people to software. However, he didn't really provide much in the way of an explanation as to why Uncommon Web (UCW) was different from other CL web packages. The key point that he should have illustrated (and, hopefully, will demonstrate in a future movie [hint, hint]) is that UCW is a continuation-based web application framework. Ok, you might ask, so what does that mean in practice? Well, for one, it means that your development model stays pretty consistent regardless of whether you are developing for the web or not. For example, say I wanted to develop a simple program that iteratively prompts a user for some numbers and prints out the total of those numbers. If I wrote this as a basic, non-web program, I might write something like the following:

(defun read-a-number (&optional (question "A number please"))
  (parse-integer (progn
		   (format t "~a: " question)
		   (read-line))))
(loop for how-many = (read-a-number "How many numbers should we read?") do (loop repeat how-many sum (read-a-number) into total finally (format t "The sum is: ~D.~%" total)))
So, my simple example consists of a single "helper" function to handle user input/output and a chunk of code that performs the logic. (Ok, it's got no error handling and you have to break it to exit, but bear with me for now ;-)). Now, what if I wanted to write that same simple program for the web? Since web apps are inherently "stateless" and each request for a number requires that you send a new page to the user, you need some way to capture "application state" (e.g. - the numbers that the user has entered so far, the maximum number of values that the user wanted to enter and the count of how many numbers have been entered so far). There are a number of ways to do this, but, in practice, it is normally done by using one (or more) of the following techniques: However, regardless which of the above techniques is used, the basic logic for the web application needs to be radically altered from my simple non-web app in order to accommodate the fact that the web is inherently stateless and we need to explicitly capture and restore session state if our application needs access to it across multiple HTML pages. A key benefit of continuation-based web application frameworks is that they take care of capturing the application state and passing it along from HTML page to HTML page without the programmer having to make major changes to their program logic. Under the covers, cookies, URL rewriting, etc may still be used; however, these "details" can be hidden from the application programmer. So, the simple example that I gave above could be written in UCW as:
(defcomponent read-a-number (widget-component)
  ((label  :accessor label  :initarg :label :initform "A number please")))
(defaction ok ((reader read-a-number) &optional number-string) (let ((num (parse-integer number-string :junk-allowed t))) (when num (answer num))))

(defaction start ((s sum)) (loop for how-many = (call 'read-a-number :label "How many numbers should we read?") do (loop repeat how-many sum (call 'read-a-number) into total finally (call 'info-message :message (format nil "The sum is: ~D." total)))))

I've deliberately left out some of the "bits & pieces" of the UCW web app in order to illustrate the similarities in the code. The full code (only slightly longer) is provided as one of Marco's examples. However, the similarities between the non-web app and the web app are readily apparent. By handling session state "behind the covers", continuation-based web application frameworks allow developers to write code for the web in a manner similar to how they write code for non-web applications without having to drastically restructure the logic of their applications. This is covered in detail in the excellent paper "Automatically Restructuring Programs for the Web". If you are interested in this approach to writing web applications, there is additional information about continuation-based web application frameworks and techniques at my links page on the topic.

emacs Copyright © 2005 by Bill Clementson