I picked up The Joy of Clojure: Thinking the Clojure Way
For those who aren’t familiar with it, Clojure is a lisp dialect that runs on the JVM, one of many languages trying to supplant Java, while maintaining access to existing tooling and infrastructure (e.g. monitoring software, Apache libraries). Other functional style languages with this goal in mind include Groovy and Scala. While you may not be running out to apply for Clojure jobs (assuming there are any), I suspect many professional programmers would find this book is quite valuable. One of the major challenges these new languages face is working around what the JVM provides: Scala, for instance has features that far outstrip Java generics, and Clojure has compelling improvements on auto-boxing.
The introduction to this book contains a lot of bravado about how great the language is, and how it will change your life. Typically I find this off-putting, however, the authors back up bold claims with very compelling and concise examples, and happily show examples of Clojure’s shortcomings (often induced by the JVM). Learning a new language that changes the programming paradigm is fairly daunting – much material covers the issues around immutable objects.
Consider one example: the Java Boolean object has a public constructor, which means you can make new objects:
Boolean f = Boolean.FALSE;
Boolean bad_false = new Boolean(false);
f.equals(bad_false); // true, as expected
f == bad_false; // not true!
Clearly this is a defect with the Java API, not a reason to switch languages in itself- there are a number of other such examples, especially against the easy targets of Swing/AWT. That said, this problem would presumably not have occurred so frequently if Java objects were immutable by default.
When confronted with the concept of immutable objects, a common objection is that copying data is obviously incredibly inefficient, which it is. When I saw Rich Hickey present Datomic (a database of immutable records), I was surprised at how well immutable data structures can be optimized, but it was not clear how he was able to construct something so complex. The answer to both concerns is in Clojure, and this book covers many optimizations in some depth when discussing Clojure collections. It is not quite as detailed as Purely Functional Data Structures
There is also a detailed discussion of threading models that are enabled by immutability (Actors / Agents). These concepts exist in several of the newer languages, which makes this well worth reading (perhaps these concepts are in some old languages too – I can’t say that I follow this end of the industry as much as I do other things). If, like me, you only look at threading code once in a while, it’s worth picking this up to read as an introduction to some new ideas.
Overall this book is well-worth reading, especially for experienced Java programmers looking to branch out in new areas, whether to explore new technologies or improve on design patterns and architectures of the old ones. It’s a heady book (took me ~12 hours to get through) – leave some time for reading and further research.