Byzantine Reality

Searching for Byzantine failures in the world around us

First Thoughts on Clojure

A lot of the buzz over the last year in programming languages has certainly been about Clojure. There’s a book about it that will be out soon, and as we’ve talked about over and over again, it’s got tons of fun features (and a lot of promise). However, it certainly seems to have a lot of quirks involved, so keep this in mind if you’re learning Clojure.

Quirk #1: The ‘print’ function forces you to also call flush or there will be unintended consequences. For example, if you were to look at this code:

(defn goo []
(print "echo> ")
(def resp (read-line))
(print resp))

You would expect to see this (for the input “foo”):

user=> (goo)
> foo

But in fact, the “echo>” doesn’t get flushed out and instead, you see this:

user=> (goo)
> foonil

Thankfully, the kind users of Stack Overflow were able to recognize what was going on (while I completely failed to). If you use println there’s no problem, but since it prints a newline it may screw up the formatting. Thankfully, there’s an easy fix:

(defn print-flush [string]
(print string)

This may end up getting added to the standard implementation of Clojure, but for now, keep it in mind if you use print.

Quirk #2: This is more of a type system issue. While meddling in a game of golf, I tried to generate and sort a list of 100 random values. The first try looked like this:

(defn gen-rands []
(sort (take 100 (repeatedly #(rand-int 9e9)))))

However, if you do this, enough of the values will be greater than Java’s max value for an integer and thus get set to Java’s max value, resulting in a very non-random result. For now, you’ll either need to use a larger data type than an Integer, or:

(defn gen-rands []
(sort (take 100 (repeatedly #(rand-int Integer/MAX_VALUE)))))

Quirk #3: Running Clojure in the first place. It’s possible to run Clojure in two different fashions, “java -jar clojure.jar” and “java clojure.lang.Repl”. They both seem to work fine, and since the first was easier to remember, I just stuck with that. However, if you do it, it seems to screw up the classpath and it’s not possible to use the community contributed libraries (clojure-contrib). Using the second method works fine, so keep that in mind most of all! It’s a pain in the ass to have none of your libraries working just because of something dumb like that.

Quirk #4: The REPL is still young, and lacks many of the features of Ruby’s REPL that I’ve come to love. You can’t hit the arrow keys to go back and forward in your typing (nor up and down to re-enter old commands), and you don’t have tab-completion. This is the only real quirk that there’s no fix for right now, but hopefully as Clojure matures the REPL will get these features.

Despite these quirks, there is a pretty cool feature about Clojure’s REPL that I have yet to see in Ruby: loading methods from a file (and reloading them) on the fly. You can type some functions in a file, and use the “load-file” function to place them all in the REPL’s namespace. This is a pretty awesome testing feature and really makes the REPL stand out. So as usual, give Clojure a try if you’ve got some downtime and see how it works for you.