About This Book

Why learn Clojure?

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.

Who should read this book?

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.

Roadmap

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.

Foundations

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.

Foundational programming languages
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.

Data types

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.

Functional programming

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.

Large-scale design

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.

Tangential considerations

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.

Code conventions

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: