The Joy of Clojure by Michael Fogus and Chris Houser is a book that tries to take the reader beyond the language syntax, and show how to write fluent, idiomatic Clojure code. It teaches how to approach programming challenges from a Functional perspective and master the Lisp techniques that make Clojure so elegant and efficient.
According to the authors, there's a "right way" to do things in Clojure. This book aims to introduce the "Clojure way of thinking” when it comes to problem solving, and help the readers recognize when they simply need to change the way they program. It does that by tackling hard software areas like concurrency, interoperability, performance, and more.
The book’s publisher, Manning, has provided InfoQ an exclusive excerpt from Chapter 9, “Exploring Clojure multimethods with the universal design pattern”.
InfoQ readers can also enjoy a 40% off The Joy of Clojure, by using the code “infoq40”.
InfoQ had a Q&A with the authors Michael Fogus and Chris Houser, about their book and Clojure:
InfoQ: Hi Chris and Mike would you like to tell us a little bit about yourselves and how you came about writing a book about Clojure?
Chouser: Fogus offered to let me be a co-author of his book -- how could I refuse?
Fogus: Chouser is being humble. The truth is that there would be no "Joy of Clojure" without him. Surprise surprise, writing a book is difficult and I can't imagine doing it on my own and admire authors who can. I'm just a normal programmer who was fortunate enough to discover Clojure in its infancy. It's never been my life-long dream to write a book, so when Manning approached me I didn't really want to do it -- in fact, I backed out at one point. However, when the possibility of working with Chouser was presented I could not refuse. The guy eats and breathes Clojure! Working with him has been extremely stimulating. Of all the people who will read our book, I have little doubt that I will have learned the most.
InfoQ: Would you like to give us a rough overview of what Clojure is? What do you think are its strongest values and how does it compete with other JVM languages?
Chouser: I think Clojure is rather unique among JVM languages in how it takes familiar concepts and breaks them down into their constituent parts and then allows you to reassemble them as you see fit. To take just one of many examples, Clojure has comprehensive support [for] traditional object-oriented features such as inheritance and polymorphism, and yet provides each of these features independent of the concept of a class, as well as independent of each other. It turns out that it's easy to recombine these if a you want to, but by having them separate you have access to surprising power in being able to combine them in non-traditional ways. This kind of thinking permeates not only how Clojure addresses objects, but also concurrency, collections and their functions, and even language syntax.
Fogus: Explaining Clojure to programmers with an OOP background is surprisingly difficult. As Chouser mentioned, the notions of inheritance, polymorphism, and encapsulation have become tightly coupled with "Class". This is potentially a big barrier to jump over when learning Clojure. Most of the more visible JVM languages enable you to write Java-flavored-X (where X is any of Scala, Groovy, etc.). Clojure is highly opinionated and requires that you rethink the ways that you've previously written software.
InfoQ: How do you see Clojure adoption? Is there a community and an ecosystem of open source projects yet?
Chouser: I just got back from the first Clojure Conj conference in North Carolina, and I'd have to say the community not only exists but is vibrant, growing, and full of smart and helpful people, most of whom are primarily interested in using Clojure to fill their real world programming needs. This has naturally led to a variety of open source projects, many of which are in Clojure Contrib which is part of the large Clojure project itself. But besides these and of course all the Java libraries that are straightforward to use directly from Clojure, there are many other Clojure-related projects springing up on places like github and google code.
Fogus: Chouser has the gist of it. However, I would like to add that while Clojure is a relative infant compared to most popular language, the growth of its ecosystem has been astounding. I doubt even Rich could have predicted the way that it has taken off.
InfoQ: What were the new additions to Clojure with verion 1.2? Chris, I’ve heard that among other things you are working on performance improvements for version 1.3. Is that correct?
Fogus: I have a slide deck at http://fogus.me/static/preso/clj1.2+ that outlines the changes in Clojure 1.2.
Chouser: That's a very nice summary. For more detail of course there's the official "Changes to Clojure 1.2": http://github.com/clojure/clojure/blob/1.2.x/changes.txt I haven't had a hand in any of Clojure 1.3's performance improvements, but Rich Hickey has's been hard at work and some of the changes he's been making will be really exciting for anyone working with Clojure in areas where Java-parity performance is desirable. The 1.3 release itself may be a way off yet, but alpha2 already has features that will make better performance possible. Not only that, most Clojure programs will see better performance without making any changes at all - every call to a named function got a bit of a boost. Finally, support for Java primitive number types in more places with less type-hinting will make it easier to achieve the best possible performance in tight-loop numeric work.
InfoQ: Michael you have recently argued in favor of community coding standards for Clojure. What was your main argument and what is the current practisepractice in open source Clojure projects?
Fogus: My post about this topic was written mostly tongue-in-cheek. I couldn't care less what personal aesthetic aethstetic someone applies to their projects. My only real point was that when straying far from the "community standard" you stand to alienate yourself from potential contributors.
Chouser: Pass. :-)
InfoQ: What would be your advice for teams that are just now starting their first Clojure project and introduce the language in their Java shop. What are the main pitfalls they should be careful about? Any “best practices”?
Chouser: Be sensitive. Almost every programmer and many managers have used or been forced to use a LISP at some point in their life, and if they're not using it now there's probably a reason for it. Being loud and obnoxious about the awesomeness of Clojure may not improve your chances of getting to use it at work. Instead I'd recommend being sympathetic about whatever pain points the team experiences because of unfamiliarity (parens, high-order functions, etc.) while emphasizing the reduced pain Clojure can deliver (succinctness from higher-level abstractions, immutability, concurrency support, etc.)
Fogus: Clojure can be a tough sell for a lot of reasons that have nothing to do with its elegance or the benefits provided. Also, the initial bump that Clojure imposes at the start of the learning curve is quite high. However, as we know, the cognitive load imposed by a programming language should not be measured by the standard felt by a newcomer. Help your friends and co-workers over that initial bump because it's a beautiful thing when Clojure finally clicks.
Chouser: As your team gets on-board with the idea of using Clojure, then it's important to use it well -- it's just as easy to create maintenance nightmares in Clojure as any other language. So read good code examples, such as from Contrib and Clojure itself, read good books about how to design solutions (I have one I could recommend if you're interested), and don't be afraid to ask code or design questions on the group forum (http://groups.google.com/group/clojure).
Fogus: Additionally, the #clojure IRC channel on Freenode is always filled with helpful Clojurians.
InfoQ: One of the main arguments in the “Clojure vs. Scala” argument is that the later allows the developer to use a OO paradigm which is more familiar, whereas Clojure is "pure functional". Would you like to comment on that?
Chouser: Yeah, it's valid question. To help, here's a handy chart that has everything you need to know on the subject:| Rocks | Sucks | --------+-------+-------+ Scala | | O_o | --------+-------+-------+ Clojure | ^_^ | | --------+-------+-------+
Fogus: Hmmm. How many units of Rocks per Sucks? I'm confused!
Chouser: Seriously, though, direct "this vs. that" programming language discussions are rarely beneficial, though I've certainly been drawn into them on occasion. Both Clojure and Scala have made the very practical decision to leverage the JVM. This demonstrates pragmatism that should be of comfort to anyone trying to get normal kinds of programming work done. Both support implementing Java classes, defining new classes and interfaces, calling Java code, being called by Java code, associating code with data, polymorphism, as well as high-order functions, immutable collections and locals, etc, so don't read too much into the phrases "functional" or "object oriented". But I would encourage anyone who is choosing a new language to pay attention to the complexity of each language feature you're likely to use. How often does using a feature bring in more complexity than you need, and how comfortable are you enduring that complexity? Also, don't ascribe more value to familiarity than you mean to.
Fogus: "Elegance and familiarity are orthogonal" -- Rich Hickey
InfoQ: As you mention on your book, one of the corner stone principles of Clojure is immutability. Since this concept might sound totally radical to Java programmers would you like to tell us a little about it?
Chouser: It was certainly radical to me when I first heard about it. I mean, how can you get anything done if you can't change anything!? Most of us however are already familiar with this is certain contexts. For example, we all know it's usually a bad idea to modify a function's arguments in the body of a function, right?function sum(an_array) { // please don't change an_array here! }Unfortunately imperative languages don't usually provide to tools to avoid mutating variables in all cases. But note even here, neither an_array nor x are ever changed, only the accumulator is updated:function sum(an_array) { var accumulator = 0; an_array.forEach( function(x) { accumulator += x; // why is it ok to change accumulator? }); return accumulator; }So what if forEach acted a little differently, giving us not only each element from an_array, but also a running total? Then when it's done, it could simply return the final total. Let's call this new version of forEach, "forAll":function sum(an_array) { var accumulator = an_array.forAll( 0, // start with zero function(running_total, x) { return running_total + x; // add to the total } ); return accumulator; }So it's certainly possible to get things done without changing locals, if the language supports it. In Clojure this is not only possible, but succinct and once you're used to it quite natural. What I called "forAll" above is called "reduce" in Clojure, and that final version of sum could be translated to something like:(defn sum [an-array] (reduce (fn [running-total x] (+ running-total x)) ; add to the total 0 ; start with zero an-array)) ; array to iterate overOr even just:(defn sum [an-array] (reduce + 0 an-array))Clojure then enforces the immutability of locals and provides a rich set of collections that works well with this style of coding so that building up and updating collections is just as natural as building up a sum. See, not so very radical. :-)
InfoQ: What do you think would be the most valuable take away from your book for people that have just found about Clojure and what for more seasoned Clojure programmers that want to take it to the next level?
Chouser: It is likely to take some effort and practice to retrain your brain to consider solutions like the above if you've spent your career so far training it to only consider imperative solutions. Similarly, Clojure's approach to several other categories of programming problems may be a bit unfamiliar, and the Joy of Clojure walks the reader through not only functional programming but also destructuring, immutable collections, lazy sequences, macros, Clojure's approach to objects, and more. Although it starts of with a concise introduction to Clojure, all but the most advanced Clojurian will learn something about how the language allows you to address problems. So I hope the take away is an additional set of ways to think about and solve the kinds of programming problems we run into every day.
Fogus: And as Chouser hinted at in his example, many of the techniques shown in our book can be applied using any programming language. However, there are enumerable advantages to realizing them at the language level rather than by convention. Functional programming, in some shape or form, is (finally) taking hold in most, if not all mainstream languages. I think that it's very important for programmers to understand the "why" and the "how" of functional programming in order to future-proof their careers.
You can find more information about Clojure, right here on InfoQ!