3

As mentioned briefly when Simon Stuart and I interviewed Jim McKeeth on the 50th episode of the podcast at delphi.org, I have recently started up a few side projects as a way of getting into Clojure. As with many, I typically find that the best way to learn a language is to have a real project to dive into. As with all initial forays into a new language, I would expect that the code I’ve written thus far is decidedly un-clojure like but that’s not unexpected with any new language.

Leading me to consider clojure

My interest was first piqued when I watched the ever impressive ThoughtWork’er Sam Newman effuse on his personal interest in Clojure during a presentation on his favourite bits of the ThoughtWorks Radar March 2012 (which it should be noted as an asie, also includes a lot on enablers for Continuous Delivery – a subject I regularly effuse about). Previously to this, I had heard of Clojure but never given it much consideration.

Clojure was created by the immensely smart Rich Hickey because he wanted a functional language with strong concurrency design that was based on Lisp that ran on an established platform. The most popular Clojure implementation is the one which runs on the JVM. Having a language with the full support of the JVM tooling and libraries cannot be understated in terms of what it brings to a platform (which RemObjects Oxygene for Java will attest to). There are also Clojure implementations for the .NET runtime and Javascript.

The primary point of appeal to me was being able to use the JVM ecosystem and be able to write JVM applications and use many of the tried and tested runtime tools of the JVM.

Turned up on an novelty interest, why stay?

It’s functional
It’s a very nice functional language, including immutable data structures, first-class functions and recursion but with a dynamic emphasis, relieving you of some of the more strongly typed influences of other languages. I believe that learning a functional language has given me an interesting perspective on programming and is a refreshing alternative to the traditional OOP paradigm.

Code as data
This is a fundamental part of Clojure, it’s a homoiconic language. This means that the code has a primary representation of data and the data structures of the language itself. Clojure applications can read, transform and produce other Clojure programs. This also leads on to one of the Clojure language’s most powerful features: macros.

This also makes the Clojure REPL incredibly powerful and easy to use, it is very common to test and evaluate all of your code in the repl. This makes testing methods and snippets of code particularly fun and easy. This also leads to greater possibilities within the IDE space, as demonstrated by Light Table.

The core Clojure syntax is extremely small and as a result, most of the syntax which you use in your day-to-day user is in fact a macro itself, take for example the syntax for a ‘when’ expression, is in fact a macro:

(defmacro when
  "Evaluates test. If logical true, evaluates body in an implicit do."
  {:added "1.0"}
  [test & body]
  (list 'if test (cons 'do body)))

Even operators like the addition operator (+), which is built in syntax in most languages is defined as a method and isn’t ‘magic’ as in many other languages.

Concurrency support
A presentation by Rich Hickey on Clojure and concurrency providing a brief overview of concurrency issues, locking, and immutability. Clojure has strong support for concurrency and has a software transactional memory, which provides ACID properties for an update of a ref. Take this example from Clojure and Concurrency on IBM Developer Works:

user=> (def droid (ref (struct item "Droid X" 0)))
#'user/droid
user=> (def history (ref ()))
#'user/history
user=> (defn place-offer [offer] 
  (dosync
    (ref-set droid (assoc @droid :current-price (get offer :amount)))
    (ref-set history (cons offer @history))    
    ))
user=> (place-offer {:user "Tony" :amount 22})
({:user "Tony", :amount 22})
user=> (println @droid @history)
{:title Droid X, :current-price 22} ({:user Tony, :amount 22})
nil

Simple, yet flexible data structures
As the Clojure rationale quotes Alan J. Perlis: “It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures.”. Typically, Clojure programs favour composing functions which operate on and manipulate basic immutable data structures rather than the complex mutable data structures that OOP programs are typically composed of.

REPL started; server listening on localhost port 55487
user=> (def vecs [[3 3 3] [3 3 3]])
user=> (apply map + vecs)
(6 6 6)

Powerful Lambda expressions
Clojure has, as you might expect, powerful lamdba expressions as with many other functional languages. There isn’t much more to add other than having first class function support in the language only adds to the flexibility of the lambda functions.

(def sum1 (fn [n1 n2] (+ n1 n2)))
(def sum2 #(+ %1 %2))

Java Interoperability
Clojure code can, of course, take advantage of Java libraries and the opposite is also true. This makes it potentially possible to have a library written in Clojure and allow Java applications take advantage of it transparently.

It’s based on Lisp
Not normally considered a strong starting position but Clojure is based on Lisp with a few key differences: core data structures are mutable but extensible and there is explicit concurrency support in the specs. For more on Lisp, please see Paul Graham’s article on the subject.

What would I use it for?

Clojure is a JVM based language so in terms of platform and application support, it is easy to use for many of the same use cases as Java. For me personally, my interest in it and initial use-case stems from the support for writing RESTful Web Services (in my case using the Compojure framework) that run on the Linux platform, an area that I feel Delphi has let me down on.

The Clojure community is friendly and supportive although still small compared to other platform incumbents. The fact that Clojure is interoperable with Java means that it is possible maintain modules of an application in Clojure and maintain the rest of the application in Java, giving you a possible bridge for bringing Clojure into existing applications with isolated risk.

Clojure support for concurrency also provides an approach for concurrency which doesn’t require explicit thread management, let’s be honest, threading can be somewhat tricky. Overall, it has been a refreshing language to learn and having access to the JVM toolset has already proven useful in profiling tools.

Further Reading

  • Clojure in Action – The Clojure book by Amit Rathore which I first purchased to learn about Clojure.
  • ClojureDocs – The most useful community documentation that I’ve found for the Clojure Core docs.
  • Clojure Toolbox – A collection of useful Clojure tools and libraries.
  • Leiningen – The most popular Clojure project management tool also handling dependency management without being maven.

Tags: ,

3 Comments

  1. paul on the 4th October 2012 remarked #

    Shouldn’t it be:

    (def sum2 #(+ %1 %2))

    instead of

    (def sum2 #(+ % %))

    ?

  2. jamiei on the 10th October 2012 remarked #

    Pal: You’re absolutely correct, I’m not sure what happened there! Thanks for the correction!

Leave a Comment