It's really good to see a book being published by the Pragmatic Programmers on the Stripes, even if it is too little, too late. I wrote an article on Stripes a few years ago, and actually, I still like how Stripes handles mapping request parameters to an object graph, but since then I have discovered the benefits of dynamic languages like Ruby, so I would never consider using a framework like Stripes, just because it means programming in Java. When I was doing Java, I felt that Stripes was a much better framework than WebWork/Struts, but for some reason flew under the radar. In fact, this blog is built using Stripes. Stripes' creator Tim Fennell always did an excellent job answering questions on the mailing list and deserved more recognition from the Java community as a whole.
It's surprising to see this book coming out now. Frankly, straight Java as a web development language is yesterday's technology, the Cobol of our generation. The JVM is still alive an well, with many great options, such as JRuby, Groovy, Scala and the best of them all, Clojure. I would love to see a Pragmatic Programmer book on Clojure, just to give some more attention to Clojure, because it is such a great language. Anyway, congrats to Tim Fennell, Frederic Daoud and the Stripes team on finally getting some acknowledgment for building a great framework and a great community.
I just posted a short screencast on how to get started with Clojure and Aquamacs:
One of the fun features of Clojure, or any Lisp I suppose, is the interactive development workflow. As you can see in the video, you write code by creating expressions that define functions and then you evaluate those functions in the REPL (Read-Eval-Print-Loop). You can redefine a function at any time. You can imagine that if you had a production system running, you could connect to it via a REPL or something like that, evaluate some expressions that redefine functions that contain bugs, and the system would be fixed with no downtime.
Here's the contents of the ~/bin/clj script:
#!/bin/bash
SRC_DIR=/Users/pbarry/src
CLOJURE_JAR=$SRC_DIR/clojure/clojure.jar
JLINE_JAR=$SRC_DIR/jline/jline-0.9.94.jar
if [ -z "$1" ]; then
java -cp $JLINE_JAR:$CLOJURE_JAR jline.ConsoleRunner clojure.lang.Repl
else
java -cp $CLOJURE_JAR clojure.lang.Script $1
fi
One problem is that running it from the command line is a lot of typing and how do a run code I have saved in a file? Something better will probably come along eventually, but here's what I did. First, save closure in /usr/local/lib/closure. Then, copy JLine jar to that directory. Finally, create a shell script at /usr/local/bin/clj with the following contents:
#!/bin/bash
CLOJURE_DIR=/usr/local/lib/clojure
CLOJURE_JAR=$CLOJURE_DIR/target/clojure-lang-1.0-SNAPSHOT.jar
if [ -z "$1" ]; then
java -cp $CLOJURE_DIR/jline-0.9.93.jar:$CLOJURE_JAR \
jline.ConsoleRunner clojure.lang.Repl
else
java -cp $CLOJURE_JAR clojure.lang.Script $1
fi
So with this, assuming /usr/local/bin is in your path, you can either run a script of invoke the REPL:
#run foo.clj
clj foo.clj
#start the REPL
clj
Now that we've got that out of the way, I thought I would provide a slight variation of the Runtime Polymorphism example:
So refer to the documentation on Runtime Polymorphism for a full explanation of what's going on here, but here's my short summary. When you call encounter, the defmulti is called first. The defmulti returns a data structure that is then used to dispatch to a defmethod that matches that data structure. The defmulti uses the value that corresponds to the key :Species in the map to construct that data structure, but the defmethod doesn't know or care where that value came from. The first list in the defmethod for encounter is what should be matched. In other words, if the defmulti returns [:foo :bar], then it calls defmethod encounter [:foo :bar]. The second list is the declaration of the arguments that the method takes.
Another little nugget in there is that the comma is whitespace. Maps are defined as a list of alternating key values, surrounded by curly braces. So {:a 1 :b 2 3 :c :d 4} is a map, but as you can see, sometimes without the commas, it can be confusing. So you can write is as {:a 1, :b 2, 3 :c, :d 4} to make it more clear where the pairs are, but it's not required.
As a result of reading Steve Yegge's latest blog rant, I have discovered a few new interesting things. Steve's rant is very anti-Java for all the right reasons, but falls apart when it gets to the "So here's what I'm going to do about it" part. He's switching to another language, one that runs on the JVM, but not Lisp, Jython, JRuby or Groovy, but for apparently no good reason, JavaScript. Not that JavaScript is a bad language, but I see reason why you would choose that over Lisp, Python or Ruby, and he fails to offer one.
The good thing is that through the comments of this post I learned about a few things, either directly or indirectly. Some of these thing have been around for a long time, but hey, I'm just learning about them.
First, there is a ground swell of support for Scala. I checked out the docs on their site and does look like a very powerful, expressive language. It seems to have many of the features of Lisp without being a Lisp dialect. It is syntactically Java-ish, but unlike Groovy, which really for some reason just seems like much-needed syntactic sugar for Java, Scala feels lieke a completely different language. In other words, and not that this is saying Groovy is a bad thing, but Groovy really isn't conceptually different than Java, where as Scala is, with things like case classes, for example. This is a language I'll have to look into some more.
There is also a mention of a new List-dialect for the JVM called Clojure. Clojure creator Rich Hickey (you need a blog Rich) recently gave a presentation on Clojure at LispNYC and the audio and slides are there. Clojure has a bunch of interesting ideas in it which he explains in the presentation. Clojure has a literal syntax for vectors (a.k.a arrays, lists) and maps (a.k.a Hashtables, Dicts) in addition to the traditional lisp lists. It is not quite a purely functional language, but strongly encourages it, making it the default programming paradigm over object-orientation. I've been wanting to check out Haskell and Erlang to get familiar with the functional programming paradigm, but Clojure might be a good way to get some exposure to that as well.
Another thing I found is Lisplets, which was created by Rich Hickey as well a few years ago. It is a Java Servlet that packages up the entire environment of an HTTP request, request parameters, cookies, session, etc, into an S-expression that is then handed off to a Lisp interpreter that listens on a socket. Lisp then reads the s-expression, does whatever it does, and then returns data to the Servlet which gets sent to the client. Mod_lisp is based on a similar concept. I think it's kind of interesting to think of web development in this manner, with a definitive layer of abstraction between the processing of request into a data structure, and then processing the request based on that data structure.