The only difference between Shakespeare and you was the size of his idiom list—not the size of his vocabulary.
—Alan Perlis
When this book was conceived, our first instinct was to create a comprehensive comparison between Clojure and its host language, Java. After further reflection, we reached the conclusion that such an approach would be disingenuous at best, and disastrous at worst. Granted, some points of comparison can’t be avoided, but Java is very different from Clojure and to try and distort one to explain the other would respect neither. Therefore, we decided that a better approach would be to focus on “The Clojure Way” of writing code.
When we become familiar with a programming language, the idioms and constructs of that language serve to define the way we think about and solve programming tasks. It’s therefore natural that when faced with an entirely new language, we find comfort in mentally mapping the new language onto the familiar old. But we plead with you to leave all of your baggage behind; be you from Java, Lisp, Scheme, C#, or Befunge, we ask you to bear in mind that Clojure is its own language and begs an adherence to its own set of idioms. You’ll discover concepts that you can connect between Clojure and languages you already know, but don’t assume that similar things are entirely the same.
We’ll work hard to guide you through the features and semantics of Clojure to help you build the mental model needed to use the language effectively. Most of the samples in this book are designed to be run in Clojure’s interactive programming environment, commonly known as the Read-Eval-Print Loop, or REPL, an extremely powerful environment for experimentation and rapid prototyping.
By the time you’re done with this book, the Clojure way of thinking about and solving problems will be another comfortable tool in your toolbox. If we succeed, then not only will you be a better Clojure programmer, but you’ll also start seeing your programming language of choice—be it Java, C#, Python, Ruby, J, or Haskell—in an entirely different light. This reassessment of topics that we often take for granted is essential for personal growth.
Paths are made by walking.
—Franz Kafka
This book isn’t a beginner’s guide to Clojure. We start fast and don’t devote much space to establishing a running Clojure environment, although we do provide some guidance on page xxix. Additionally, this isn’t a book about Clojure’s implementation details, but instead one about its semantical details. This is also not a “cookbook” for Clojure, but instead a thorough investigation into the ingredients that Clojure provides for creating beautiful software. Often we’ll explain how these ingredients mix and why they make a great match, but you won’t find complete recipes for systems. Our examples directly address the discussion at hand and at times leave exposed wiring for you to extend and thus further your own knowledge. It wouldn’t serve us, you, or Clojure to try to awkwardly mold a comprehensive lesson into the guise of a book-length project. Often, language books spend valuable time halfheartedly explaining “real-world” matters totally unrelated to the language itself, and we wish to avoid this trap. We strongly feel that if we show you the “why” of the language, then you’ll be better prepared to take that knowledge and apply it to your real-world problems. In short, if you’re looking for a book amenable to neophytes that will also show you how to migrate Clojure into existing codebases, connect to NoSQL databases, and explore other “real-world” topics, then we recommend the book Clojure in Action by Amit Rathore (Manning, 2011).
Having said all of that, we do provide a short introduction to the language and feel that for those of you willing to work hard to understand Clojure, this is indeed the book for you. Additionally, if you already have a background in Lisp programming, then much of the introductory material will be familiar, thus making this book ideal for you. Though by no means perfect, Clojure has a nice combination of features that fit together into a coherent system for solving programming problems. The way Clojure encourages you to think about problems may be different than you’re used to, requiring a bit of work to “get.” But once you cross that threshold, you too may experience a kind of euphoria, and in this book we’ll help you get there. These are exciting times, and Clojure is the language we hope you’ll agree is an essential tool for navigating into the future.
We’re going to take you on a journey. Perhaps you’ve started on this journey yourself by exploring Clojure beforehand. Perhaps you’re a seasoned Java or Lisp veteran and are coming to Clojure for the first time. Perhaps you’re coming into this book from an entirely different background. In any case, we’re talking to you. This is a self-styled book for the adventurous and will require that you leave your baggage behind and approach the enclosed topics with an open mind. In many ways, Clojure will change the way you view programming, and in other ways it’ll obliterate your preconceived notions. The language has a lot to say about how software should be designed and implemented, and we’ll touch on these topics one by one throughout this book.
Every so often, a programming language comes along that can be considered foundational. Occasionally a language is invented that shakes the foundations of the software industry and dispels the collective preconceived notions of “good software practices.” These foundational programming languages always introduce a novel approach to software development, alleviating if not eliminating the difficult problems of their time. Any list of foundational languages inevitably raises the ire of language proponents who feel their preferences shouldn’t be ignored. But we’re willing to take this risk and therefore list the following programming languages in this category.
| Year | Language | Inventor(s) | Interesting reading |
|---|---|---|---|
| 1957 | Fortran | John Backus | John Backus, “The History of Fortran I, II, and III,” IEEE Annals of the History of Computing 20, no. 4 (1998). |
| 1958 | Lisp | John McCarthy | Richard P. Gabriel and Guy L. Steele Jr., “The Evolution of Lisp” (1992), www.dreamsongs.com/Files/ HOPL2-Uncut.pdf. |
| 1959 | COBOL | Design by committee | Edsger Dijkstra, “EWD 498: How Do We Tell Truths That Might Hurt?” in Selected Writings on Computing: A Personal Perspective (New York: Springer-Verlag, 1982). |
| 1968 | Smalltalk | Alan Kay | Adele Goldberg, Smalltalk-80: The Language and Its Implementation (Reading, MA: Addison-Wesley, 1983). |
| 1972 | C | Dennis Ritchie | Brian W. Kernighan and Dennis M. Ritchie, The C Programming Language (Englewood Cliffs, NJ: Prentice Hall, 1988). |
| 1972 | Prolog | Alain Colmerauer | Ivan Bratko, PROLOG: Programming for Artificial Intelligence (New York: Addison-Wesley, 2000). |
| 1975 | Scheme | Guy Steele and Gerald Sussman | Guy Steele and Gerald Sussman, the “Lambda Papers,” mng.bz/sU33. |
| 1983 | C++ | Bjarne Stroustrup | Bjarne Stroustrup, The Design and Evolution of C++ (Reading, MA: Addison-Wesley, 1994). |
| 1986 | Erlang | Telefonaktiebolaget L. M. Ericsson | Joe Armstrong, “A History of Erlang,” Proceedings of the Third ACM SIGPLAN Conference on History of Programming Languages (2007). |
| 1987 | Perl | Larry Wall | Larry Wall, Tom Christiansen, and Jon Orwant, Programming Perl (Cambridge, MA: O’Reilly, 2000). |
| 1990 | Haskell | Simon Peyton Jones | Miran Lipovaĉa, “Learn You a Haskell for Great Good!” http://learnyouahaskell.com/. |
| 1995 | Java | Sun Microsystems | David Bank, “The Java Saga,” Wired 3.12 (1995). |
| 2007 | Clojure? | Rich Hickey | You’re reading it. |
Like them or not, there’s little dispute that the listed programming languages have greatly influenced the way that software is constructed. Whether Clojure should be included in this category remains to be seen, but Clojure does borrow heavily from many of the foundational languages and also from other influential programming languages to boot.
Chapter 1 starts our journey and provides some of the core concepts embraced by Clojure. These concepts should be well understood by the time you’ve finished the chapter. Along the way, we’ll show illustrative code samples highlighting the concepts at hand (and sometimes even pretty pictures). Much of what’s contained in chapter 1 can be deemed “The Clojure Philosophy,” so if you’ve ever wondered what inspired and constitutes Clojure, we’ll provide that for you.
Chapter 2 provides a fast introduction to specific features and syntax of Clojure.
Chapter 3 will address general Clojure programming idioms that aren’t easily categorized. From matters of truthiness and style to considerations of packaging and nil, chapter 3 is a mixed bag. All of the topics are important in their own right, and to understand them is in many ways a start to understanding a large portion of idiomatic Clojure source code.
The discussion on scalar data types in chapter 4 will be relatively familiar to most programmers, but some important points beg our attention, arising from Clojure’s interesting nature as a functional programming language hosted on the Java Virtual Machine. Java programmers reading this book will recognize the points made concerning numerical precision (section 4.1), and Lisp programmers will recognize the discussion on Lisp-1 versus Lisp-2 (section 4.4). Programmers will appreciate the practical inclusion of regular expressions as first-class syntactical elements (section 4.5). Finally, long-time Clojure programmers may find that the discussion of rationals and keywords (sections 4.2 and 4.3, respectively) sheds new light on these seemingly innocent types. Regardless of your background, chapter 4 will provide crucial information in understanding the nature of Clojure’s underappreciated scalar types.
Clojure’s novel persistent data structures will be covered in chapter 5; this should be enlightening to anyone wishing to look more deeply into them. Persistent data structures lie at the heart of Clojure’s programming philosophy and must be understood to fully grasp the implications of Clojure’s design decisions. We’ll only touch briefly on the implementation details of these persistent structures, because they’re less important than understanding why and how to use them.
Chapter 6 will deal with the nebulous notions of immutability, persistence, and laziness. We’ll explore Clojure’s use of immutability as the key element in supporting concurrent programming. We’ll likewise show how, in the presence of immutability, many of the problems associated with coordinated state change disappear. Regarding laziness, we’ll explore the ways that Clojure leverages it to reduce the memory footprint and speed execution times. Finally, we’ll cover the interplay between immutability and laziness. For programmers coming from languages that allow unconstrained mutation and strict evaluation of expressions, chapter 6 may prove to be an initially mind-bending experience. But with this mind-bending comes enlightenment, and you’ll likely never view your preferred programming languages in the same light.
Chapter 7 will tackle Clojure’s approach to functional programming full-on. For those of you coming from a functional programming background, much of the chapter will be familiar, although Clojure will present its own unique blend. But like every programming language dubbed “functional,” Clojure’s implementation will provide a different lens by which to view your previous experience. For those of you wholly unfamiliar with functional programming techniques, chapter 7 will likely be mind-bending. In coming from a language that centers on object hierarchies and imperative programming techniques, the notion of functional programming seems alien. But we believe Clojure’s decision to base its programming model in the functional paradigm to be the correct one, and we hope that you’ll agree.
Clojure can be used as the primary language for any application scale, and the discussion of macros in chapter 8 might change your ideas regarding how to develop software. Clojure as a Lisp embraces macros, and we’ll lead you through the process of understanding them and realizing that with great power comes great responsibility.
In chapter 9, we’ll guide you through the use of Clojure’s built-in mechanisms for combining and relating code and data. From namespaces to multimethods to types and protocols, we’ll explain how Clojure fosters the design and implementation of large-scale applications.
Clojure is a symbiotic programming language, meaning that it’s intended to run atop a host environment. For now, the host of choice is the Java Virtual Machine, but the future bodes well for Clojure becoming host-agnostic. In any case, Clojure provides top-notch functions and macros for interacting directly with the host platform. In chapter 10, we’ll discuss the ways that Clojure interoperates with its host, focusing on the JVM throughout.
Clojure is built to foster the sane management of program state, which in turn facilitates concurrent programming, as you’ll see in chapter 11. Clojure’s simple yet powerful state model alleviates most of the headaches involved in such complicated tasks, and we’ll show you how and why to use each. Additionally, we’ll address the matters not directly solved by Clojure, such as how to identify and reduce those elements that should be protected using Clojure’s reference types.
The final part of this book will discuss topics that are equally important: the design and development of your application viewed through the lens of the Clojure Philosophy. In chapter 12, we’ll discuss ways to improve your application’s performance in single-threaded applications. Clojure provides many mechanisms for improving performance, and we’ll delve into each, including their usage and caveats where applicable. And to wrap up our book, in chapter 13, we’ll address the ways that Clojure changes the ways that you look at tangential development activities, such as the definition of your application domain language, testing, error-handling, and debugging.
The source code used throughout this book is formatted in a straightforward and pragmatic fashion. Any source code listings inlined within the text, for example (:lemonade :fugu), will be formatted using a fixed-width font and highlighted. Source code snippets outlined as blocks of code will be offset from the left margin, formatted in a fixed-width font, and highlighted to stand out:
(def population {::zombies 2700 ::humans 9})
(def per-capita (/ (population ::zombies) (population ::humans)))
(println per-capita "zombies for every human!")
Whenever a source code snippet indicates the result of an expression, the result will be prefixed by the characters ;=>. This particular sequence serves a threefold purpose:
(def population {::zombies 2700 ::humans 9})
(/ (population ::zombies) (population ::humans))
;=> 300Additionally, any expected display in the REPL that’s not a returned value (such as exceptions or printouts) will be denoted with a leading ; prior to the actual return value:
(println population)
; {:user/zombies 2700, :user/humans 9}
;=> nil
In the previous example, the map displayed as {:user/zombies 2700, :user/humans 9} is the printed value, whereas nil denotes the returned value from the println function. If no return value is shown after an expression, then you can assume that it’s either nil or negligible to the example at hand.
READING CLOJURE CODE When reading Clojure code, skim it when reading left-to-right, paying just enough attention to note important bits of context (defn, binding, let, and so on). When reading from the inside out, pay careful attention to what each expression returns to be passed to the next outer function. This is much easier than trying to remember the whole outer context when reading the innermost expressions.
All code formatted as either inline or block-level is intended to be typed or pasted exactly as written into Clojure source files or a REPL. We generally won’t show the Clojure prompt user> because it’ll cause copy/paste to fail. Finally, we’ll at times use the ellipsis ... to indicate an elided result or printout.
Code annotations accompany many of the listings, highlighting important concepts. In some cases, numbered bullets link to explanations that follow the listing.
If you don’t currently have Clojure, then we recommend you retrieve the Clojure REPL package (Cljr) created by David Edgar Liebke, located at http://joyofclojure.com/cljr and installing it via the following instructions.
Run the following from your operating system’s console:
java -jar cljr-installer.jar
If your chosen download method appended a .zip file extension to the Cljr package, then the following is fine:
java -jar cljr-installer.jar.zip
You’ll see output from Cljr indicating its installation and package download progress. Once it has completed, you’ll see instructions for running Clj similar to the following:
Cljr has been successfully installed. Add $HOME/.cljr/bin to your PATH:
$ export PATH=$HOME/.cljr/bin:$PATH
Run 'cljr help' for a list of available commands.
Following the steps displayed, run Cljr.
The Cljr package runs a Clojure REPL (Read/Eval/Print Loop) for version 1.2.0—the same version corresponding to this book. When you launch the Cljr program, you’ll see the window shown in the figure below.
The Cljr REPL is similar to the stock Clojure REPL, but with additional convenient features as explained at http://github.com/fogus/cljr.
The book won’t proceed under the assumption that you’re using Cljr but will work regardless of your own personal REPL setup—as long as you’re running Clojure version 1.2.
Source code for all working examples in this book is available for download from the publisher’s website at www.manning.com/TheJoyofClojure.
Purchase of The Joy of Clojure includes free access to a private web forum run by Manning Publications where you can make comments about the book, ask technical questions, and receive help from the authors and from other users. To access the forum and subscribe to it, point your web browser to www.manning.com/TheJoyofClojure. This page provides information on how to get on the forum once you are registered, what kind of help is available, and the rules of conduct on the forum.
Manning’s commitment to our readers is to provide a venue where a meaningful dialogue between individual readers and between readers and the authors can take place. It is not a commitment to any specific amount of participation on the part of the authors, whose contribution to the AO remains voluntary (and unpaid). We suggest you try asking the authors some challenging questions lest their interest stray!
The Author Online forum and the archives of previous discussions will be accessible from the publisher’s website as long as the book is in print.
The figure on the cover of The Joy of Clojure is captioned “The Confidence Man,” which, in 19th century France, could mean anything from a healer or medicine man to a card shark or money lender or traveling salesman. The illustration is taken from a 19th-century edition of Sylvain Maréchal’s four-volume compendium of regional dress customs published in France. Each illustration is finely drawn and colored by hand. The rich variety of Maréchal’s collection reminds us vividly of how culturally apart the world’s towns and regions were just 200 years ago. Isolated from each other, people spoke different dialects and languages. In the streets or in the countryside, it was easy to identify where they lived and what their trade or station in life was just by their dress.
Dress codes have changed since then and the diversity by region, so rich at the time, has faded away. It is now hard to tell apart the inhabitants of different continents, let alone different towns or regions. Perhaps we have traded cultural diversity for a more varied personal life—certainly for a more varied and fast-paced technological life.
At a time when it is hard to tell one computer book from another, Manning celebrates the inventiveness and initiative of the computer business with book covers based on the rich diversity of regional life of two centuries ago, brought back to life by Maréchal’s pictures.