Clojure++

I was lucky enough to be able to make it to San Francisco last week, not for you know what (who has two grand?), but to see coworkers and friends. It sure didn't hurt that JavaOne brought a lot of talent into the area, and I took advantage of that by attending Rich Hickey's talk at the special edition of the Bay Area Clojure User Group meetup. As Sean Corfield notes in the meetup feedback, the talk was both "entertaining and thought provoking," which I think is about all you can ask of a talk about language internals.

The big takeaway, I'd say, is that Rich is interested in making Clojure a language that runs code like the stuff we write run really damn fast. At the moment, he's working on static linking and enhanced primitive support, which looks like this:

(defn fib [n]
  (if (<= n 1)
    1
    (+ (fib (dec n)) (fib (- n 2)))))

(time (fib 38))
"Elapsed time: 3565.579 msecs"

;; hint arg and return
(defn ^:static fib ^long [^long n]
  (if (<= n 1)
    1
    (+ (fib (dec n)) (fib (- n 2)))))

(time (fib 38))
"Elapsed time: 395.365 msecs"

That's right: add a few annotations to the method signature, and get 9x performance. Thanks to Clojure's autoboxing and promotion of ints to longs, this works for just about any values you'd want to use here.

There is one exception, and it was an important part of what Rich had to say last Monday: this function, and most numeric functions in Clojure, will no longer auto-promote values to Big numbers to avoid overflowing longs and doubles. This is already somewhat controversial, and will no doubt remain so, but Rich did a good job of explaining its necessity as a workaround for the JVM's inability to handle values that might be objects or primitives. Inconveniencing legitimate consumers of arbitrary precision math (you know who you are!) to make everyone else happier is a tradeoff that makes sense to me.

The vision behind this work is the enablement of functional patterns with bare metal performance - mapping a statically linked function over an array of primitives should be no slower than a corresponding imperative loop. Performance of idiomatic code will be a feature of Clojure, which is pretty uncommon.

Rich's presentation and the gaggle of smart people asking questions yielded many other gems throughout the night. Clojure seems to be on course for a solid amount of additional development. Parallelism will be improved via fork/join and some cleanup of binding semantics. Pods - more on these after Clojure Conj - will help bring side-effect laden Java code into the fold in a clean way. Clojure's Java underpinnings will eventually move to Clojure, and provide a much more solid foundation for tooling along with them. These changes will largely be "additions" to the language or entirely transparent, unlike some of the important changes to semantics slated for the near future.

This, I think, is probably going to be the story of Clojure - the language - from here on out. Don't expect an actor model or an object system from the core implementation (add them if you really want them!). Do expect a healthy community of interesting, performant libraries and a language that will continue to take whatever steps are necessary to replace Java in your day to day life: this is the clear goal of its creator.