Monday, June 9, 2008

The beginner's guide to Clojure

What is Clojure, I hear you ask? Well, as you know, in the last decade or so, Sun's Java thing has taken the world by storm. Few can deny that it is acceptably fast for most purposes, nor that it will run just about anywhere with sufficient prodding and coaxing, nor even that it has plenty of handy libraries for every occasion, and a GUI library which, while revolting, is a great deal less revolting than most other very cross-platform GUI things; I'm looking at you, TK.

The problem is that Java the Language, as opposed to Java the Virtual Machine or Java the Rather Strong Sort Of Coffee, Now Out Of Favour And Replaced By Varieties From Famine Hotspots, is really, really, amazingly bloody awful. Shockingly bad. It's like C++ with a memory manager stuffed in and most of the useful stuff sneaked out the back door. Things aren't all bad; the Java implementers are slowly adding scary things like generics, and who knows, there may be closures and multiple inheritance and unsigned integers before the decade is out! Okay, well maybe the century. Anyway, the point is that as it stands Java is unusable, except by masochistic website developers who somehow think that it being a pseudo-industry-standard forgives all, and that writing endless reams of crap again and again and again builds character, anyway.

How, then, do we get the admitted convenience of the JVM without having to wrap things in endless other things just to make them vaguely usable? Fortunately, more Java-tolerant people than I have looked into the issue, and have produced other languages targeting the JVM. Lots of them. They are legion.

Some are re-implementations of nice-ish languages, like Python, Ruby, and Common Lisp. These, sadly, tend to have one thing in common; they don't work properly. Then there are endless Schemes, as is required for any VM whatsoever, a variety of scary BASIC derivatives, frankly sick and twisted things like COBOL for the JVM, nasty things designed by XML fetishists... and then there are the oddities. Clojure is one such, as is Scala. These are effectively new languages, albeit heavily influenced by older tongues, for the JVM.

Clojure, which, I think, was the original point of this ramble, is a Lispish, brackety creature; it also has funny concurrency stuff, of which more anon. It's really quite nice, though it has its quirks.

A big problem with these funny little new languages is generally that there is no acceptable way to work with them without going mad. There's no IDE, no tools, no debugger... Fortunately, this turns out not to be the case with Clojure. There is a port of the SLIME backend (SLIME is a nice Emacs interaction mode for Common Lisp). The one tiny little problem is that nowhere on the great wide Internet, as far as I can see, is there any guide to getting this stuff set up.

Here we go, then.

First, you'll want the SVN version of Clojure. The packaged version Will Not Do for these purposes, it seems. Actually, aha, fooled you, you'll want Apache Ant first; it is a scary tool for building Java projects. Yes, of course it has plenty of XML; did you even need to ask? Get it and install it, then in your checkout, type 'ant jar'. This will cause a JAR file (a ZIP of compiled Java code) to appear before you in short order.

You'll then want to get all three things from here. One is a script to run Clojure conveniently, one is a standard Emacs mode, and the third is the SWANK backend. Set up the script, and put the other two somewhere.

Right. You will now want a .emacs file something like this:


(setq slime-lisp-implementations
'((clojure ("/Users/robertsynnott/bin/clojure") :init clojure-init)))

(add-to-list 'load-path "/Users/robertsynnott/clojure/clojure-mode/")
(require 'clojure-mode)

(add-to-list 'load-path "/Users/robertsynnott/clojure/swank-clojure/")
(require 'swank-clojure)
(add-to-list 'load-path "/Users/robertsynnott/lisp/slime/")

(require 'slime)

(set-language-environment "UTF-8")
(setq slime-net-coding-system 'utf-8-unix)
(slime-setup)


Obviously, you should substitute paths on your own system; mine has quite enough to be doing.

You may now restart Emacs, and type M-x slime. All going well, you should be presented with a Clojure REPL. You may now open a file to put stuff in; the mandated extension is '.clj', displeasing in that, to me at least, it suggests both Common Lisp and Java; Clojure is neither. Possibly I am being over-paranoid. Depending on the phase of the moon, you may or may not have to do M-x clojure-mode to get things to behave, at that point.

You now have Clojure running! Try typing '4'; you will note that you get '4' in return. This pleasing result can be replicated for even very large numbers.

What's Clojure like? Lisp-ish... mostly. There are extra types of bracket, you see. [] are for arrays and various other things; {} are for dictionaries/hash tables. A function looks like this:

(defn bla ([x] x)
([x y] (+ x y)))


You will note that there's a weird pattern matching thing going on here; (bla 4) will return 4 while (bla 4 5) will return 9. lets are similar:

(let [[a b c] [1 2 3 4]]
b)

That gives you 2; it's a little like a combination between a Common Lisp let and destructuring-bind. I actually quite like this; it looks like the sort of thing CL should have.

There are also multimethods! They're not as cabable as those in CLOS, to be sure, but a fair bit better than Java's OO system. They operate on dictionaries as objects, for some reason.

Then there are the weird concurrency things. One is a Software Transactional Memory system, meaning that it behaves a bit like a database, it seems; the other is something similar to Erlang's message passing. I like these; so much nicer than mucking around with proper threads.

There are also quite nice semantics for talking to scary ol' Java, when it becomes necessary.

I've barely scratched the surface, of course, but the online guide is well worth a look, if you're interested.

Would I actually use it? Hmm, well, now, I'm not sure. There's certainly an appeal; if I was doing something which might ordinarily call for Java, Clojure might be a nice substitute. Your mileage may vary, of course, but I'd say it's definitely worth looking into.

5 comments:

dabd said...

Hi Robert,

Just a small correction: slime-lisp-implementations should be a list of lists, so there is an extra pair of parenthesis missing in your example.

(setq slime-lisp-implementations
'((clojure ("~/bin/clojure") :init clojure-init)))

Thansk,
dabd

Robert Synnott said...

Oops, yes, I removed my SBCL one, and forgot to fix the brackets...

sjf said...

Rob, you are a fucking technical writing genius. I think I actually laughed out loud. You should write a book.

Robert Synnott said...

The writing style is more or less stolen from Verity Stob, I'm afraid...

sinewalker said...

Clojure looks like lots of fun to play with after I've finished studying for my SCJP exam (assuming I haven't gone out of my mind before then).

I actually came to this blog entry after trying to read a JavaWorld article about the arguments in java-land over adding closures to that language! I thought "there has to be a better way ... can't I use lisp on the JVM and access Java classes from it somehow?" I guess Clojure's not such a bad name after all ;-)

Oh, and next time you edit your ~/.emacs and need to re-load it, don't bother restarting emacs. Do M-x load-file and enter ~/.emacs at the minibuffer prompt.