It was a huge pleasure to be speaking at a No Fluff Just Stuff conference again, it's been much too long. This was a good show with a lot of folks coming down from Vancouver, BC to attend.
This was an odd show for me, as we didn't do any Tapestry talks at all. However, all three of my talks (an introduction to Cappuccino, and two talks on Clojure) were well attended, with good questions and some fun discussions between sessions. I'm looking forward to doing these same sessions, with a number of improvements, in the Spring when NFJS starts back up.
Interestingly, I was busy writing Clojure code almost continuously in the back row of other speaker's sessions ... but this didn't stop me from appreciating Scott Davis's great talks on Grails, and on "deconstructing Web 2.0". Also, I had a lot of interaction with Brian Goetz ("are all web application's broken"). As usual, as soon as you mix Java with concurrency, it's a bit sobering. Tapestry helps here, but is not a complete panacea against some of the "nightmare scenarios" that may become more commonplace as the number of CPU cores increases.
I'm getting more adept at advanced Clojure; I've been busy adapting the concept of
parameter destructuring to pulling data out of the request path and query parameters.
(defaction increment-count
{:path "count/increment"}
[env]
[count :int] ; destructure the value after "/increment" as an integer
(send-redirect env (link env show-counter [(inc count)])))
This defines a Cascade action, mapped to the "count/increment" path. A number is expected to follow (i.e., /count/increment/4
) and the job of this action is to increment that value and redirect the user to the show-counter view.
Cascade actions are still functions, thus the normal parameter declaration: [env]
. Cascade views and actions always take a single parameter, a map called "the environment" that provides access to Cascade-specific values as well as Servlet API objects.
The path destructuring follows: [count :int]
which destructures the first "extra path" value as an integer. There's a number of built-in parsers referenced by keywords such as :int, or you can supply a function that takes a string and returns a value. If another pair of values is given, that applies to the next value in the path.
I'm finding this a pretty elegant way to express this secondary aspect of mapping URLs to view and actions; there's additional syntax for destructuring query parameters instead of path values. I may extend this further, to handle default values for missing terms in the path.
I try to capture some of this in my Clojure talks; the idea of growing the language up, adding the new features you need. From one perspective, this is just a domain specific language, but in the Lisp world, that concept is so deeply entrenched that there isn't even a word for it beyond "programming". This is one part of the overall Clojure picture that gets me very excited, and I'm continuing to struggle with how to express this to people for whom even the Lisp syntax is alien and off-putting.