Clojure

While I'm talking about new Lisps, I should mention Clojure, a new Lisp with close JVM integration and fancy concurrency support. I've been meaning to write something in it and post about the experience, but it may be a while before I get around to that. So here's the quick summary:

Clojure has the usual features of modern Lisps: lisp-1-ness, case-sensitivity (because it's hard to do case-insensitivity right), distinguishing () from nil from |nil|, pure symbols, shorter names, modules. It's quite clean, although Lispers should watch out for the renamings (familiar names like cons and do aren't what you expect). There is destructuring in binding constructs, and lambda is really case-lambda. Its Lispy core looks quite good (although as I said, I haven't used it much yet), and it closely resembles the orthodox modern Lisp.

Except for one thing: most data is immutable. Clojure aims at the most popular open problem in languages today: safe concurrency. Like Erlang, it tries to provide state only in forms that are easier to use safely in concurrent programs. Clojure has three: mutable special variables (since their bindings are per-thread), software transactional memory, and reactive message-passing. (See those pages for explanations and examples. There's also a wiki with more examples.) What it doesn't have is the ordinary mutation we take for granted in other Lisps. There's no setf, no mutable arrays or hashtables, no push.

Fortunately there's a lot of careful support for immutable collections, including syntax for [vectors] and {maps}, and generic iteration (even on Java collections!). It includes some useful functions that are often forgotten, such as mapcat and range. Clojure may not have state, but it tries to do the alternatives well enough that you don't feel the lack.

The ultimate alternative to language limitations is an FFI. Clojure is implemented in Java and runs on the JVM, so its FFI takes the form of extensive Java integration: nil is Java null, some interfaces are supported (in both directions!), and it's very easy to call Java code. There are some downsides to staying so close to Java: there's no tail-call optimization, and since threads are Java threads, their number is limited (potentially annoying, in a concurrent language). The upside is that it inherits all sorts of functionality from Java - the VM, massive libraries, even mutable data if you need it. This goes a long way toward explaining the completeness and high quality of the implementation.

There's something I'm wondering about, though. How do you pronounce Clojure? Same as "closure"? Or with /ʤ/ as in "Java"?

6 comments:

  1. It's pronunced "closure"--I was there at the Western Mass Developer's Group where Hickey spoke and he said it that way.

    ReplyDelete
  2. Except the "Modern Lisp" you're referring to is actually Scheme, looking at the features you present.

    These days, "Modern Lisp" means Common Lisp.

    ReplyDelete
  3. Actually, you're almost right, Mikael. These days, "Bigot Lisp" means Common Lisp.

    Scheme doesn't have half the features from the article.

    ReplyDelete
  4. Scheme has many of the features popular in new Lisps, but it comes from a different culture, and the feel of the language is quite different. I think the main reason is that the new Lisps are intended as tools to program in, so they pay much more attention to usability. Scheme usually hasn't (much to the annoyance of would-be Schemers), so outside of its great kernel, it can be frustratingly primitive. Maybe I should finish the post I was writing about this.

    ReplyDelete
  5. Four years later, watch scheme-reports.org.

    ReplyDelete

It's OK to comment on old posts.