When Stuart Halloway's
Programming Clojure
came out in May, I picked up a copy and have been reading through
it and practicing with the
Project Euler problems.
First off, it is a great book! Second off, it introduces a seriously interesting
programming language.
Clojure is a
Lisp
dialect designed to run on
Java Virtual Machine
(JVM). This combination is what makes Clojure very powerful: you
get the power of a mature virtual machine with access to any
existing Java libraries, combined with the dynamic, functional
style of Lisp. Imagine being able to continue to use the code and
libraries you any others have spent years developing from a new
programming environment.
Layering a language on top of the JVM is
not a new concept. Jython,
JRuby,
Groovy, and others did it years
ago. But to some extent, these languages serve as a mere face-lift
to the verbose syntax of Java. These languages were ported or
created for the JVM to harness the power of existing Java libraries
and platforms, while providing a prettier language.
While Clojure does offer a new syntax, it has a much more fundamental
contribution to the Java world: strong concurrency primitives. (It
should be noted that Scala offers
this benefit as well.)
Clojure takes a hard-line approach to the
arch-enemy of concurrency: shared state. Clojure allows programmers
to easily write concurrent programs that can execute on multiple
processors or cores. This ability comes from several facets of
Clojure:
- Immutable data
- Preferring "pure" functions by making the programmer explicitly
state where shared state is accessed
- Multiple models for transactions and locks
Almost anyone who has experience writing threaded Java code, knows
how difficult it is to ensure that multiple threads can execute in
parallel without causing awful race conditions and subtle bugs.
Luckily, Clojure addresses these shortcomings by using its own
concurrency models.
Stuart's book begins by discussing the syntax
of Clojure and demonstrates Clojure's ability to interact with
regular Java classes. The book moves into the list-based world of
Lisp with functional programming techniques, including lazy
evaluation. The book then moves into advanced topics, including
concurrency, macros, and Clojure's form of polymorphism,
multimethods. The book concludes with a short chapter on testing
Clojure code, working with SQL databases, and doing web
development.
Through the book, we work on building an
Ant replacement in Clojure. The most
interesting take-away from this ongoing example is the use of
actual Clojure code for the build
DSL,
removing the need for Ant's build.xml. The code-as-data concept is
very elegant, resulting in a DSL that is very clear yet lacks XML's
verbosity.
I also found the Snake game to be an excellent example
of an application sharing state in a safe way using the Clojure
transaction primitives.
The book gave me a great appreciation of
the Lisp family of languages. The only wart that bothered me about
Clojure was that it seems that at times the programmer must be too
aware of the specific implementation of Clojure on the JVM. For
instance, Clojure's recursion is at times hampered by the lack of
Tail Call Optimization
on the JVM. Because of this lack, the programmer must determine
which work-around is most appropriate for his problem. Regardless,
Clojure feels very clean and precise.
The book also clearly
provides best practices and examples of idiomatic Clojure.
I look forward trying Clojure out in my projects. As I mentioned, I have been
working through
the Project Euler problems (my answers are definitely not ideal).
I would highly recommend the book to anyone who works in Java. I also
believe the book is an excellent introduction to functional
programming--I have read the
Real World Haskell and
Programming Erlang
books with some difficultly, but
Programming Clojure
just clicked in my mind.