When all is said and done, Clojure is yet another Lisp dialect. It will have the same language limitations and many of the same considerable strengths. Understanding Clojure starts with understanding Lisp.
After Fortran, Lisp is the oldest commercially active language. It’s a functional language but not a pure functional language. The acronym stands for LISt Processing, and early on, you’ll see why. Lisp has some interesting characteristics:
Lisp is a language of lists. A function call uses the first list element as the function and the rest as the arguments.
Lisp uses its own data structures to express code. Lisp followers call this strategy data as code.
When you combine these two ideas, you get a language that’s ideal for metaprogramming. You can arrange your code as named methods in a class. You could arrange those objects into a tree, and you have a basic object model. You could also build a prototype-based code organization with slots for data and behavior. You can build a pure-functional implementation. It’s this flexibility that allows Lisp to morph the language into just about any programming paradigm you want.
In Hackers and Painters [Gra04], Paul Graham chronicles the story of how a small development team used Lisp and its powerful programming model to defeat much larger companies. They believed Lisp provided a significant programming advantage. In fact, they paid more attention to start-ups posting jobs requiring Lisp and other higher-level languages.
The primary Lisp dialects are Common Lisp and Scheme. Scheme and Clojure are from the same family of dialects called lisp-1, and Common Lisp is a lisp-2 dialect. The primary difference between the dialect families has to do with the way namespaces work. Common Lisp uses a separate namespace for functions and variables, while Scheme uses the same namespace for both. With the Lisp side of the equation behind us, let’s move on to the Java side.
Every Lisp dialect caters to its audience. For Clojure, one of the most important characteristics is the JVM. With Scala, you saw that having a commercially successful deployment platform can make all the difference in the world. You don’t have to sell a Clojure server to your deployment people to use it. Though the language is relatively new, you can access the tens of thousands of Java libraries to do just about anything you need.
Throughout this chapter, you’ll see evidence of the JVM, in the way you invoke it, in the libraries we use, and in artifacts we create. But you’ll also see liberation, too. Clojure is functional, so you’ll be able to apply advanced concepts to your code. Clojure is dynamically typed, so your code will be more concise, easier to read, and more fun to write. And Clojure has the expressiveness of Lisp.
Clojure and Java desperately need each other. Lisp needs the market place that the Java virtual machine can offer, and the Java community needs a serious update and an injection of fun.
The last piece of the equation for this language is the set of libraries. Clojure is a functional language, with emphasis on functions without side effects. But when you do use mutable state, the language supports a number of concepts to help. Transactional memory works like transactional databases to provide safe, concurrent access to memory. Agents allow encapsulated access to mutable resources. We’ll cover some of these concepts in day 3.
Impatient are you? Start with Clojure, we will.