C-style ad hoc debauchery.
Download from Wow! eBook <www.wowebook.com>
26
CHAPTER 2 Drinking from the Clojure firehose
2.3.2
Defining functions
An anonymous (unnamed) Clojure function can be defined as a special form. A spe-
cial form is a Clojure expression that’s part of the core language, but not created in
terms of functions, types, or macros.
An example of a function taking two elements that returns a set of those elements
would be defined as
(fn mk-set [x y] #{x y})
;=> #<user$eval__1$mk_set__2 user$eval__1$mk_set__2@d3576a2>
Entering this function definition in a Clojure REPL gives us a seemingly strange result.
This is because the REPL is showing its internal name for the function object returned
by the fn special form. This is far from satisfying, given that now that the function has
been defined, there’s no apparent way to execute it. It should be noted that the mk-set
symbol is optional and doesn’t correspond to a globally accessible name for the func-
tion, but instead to a name internal to the function itself used for self-calls. Recall from
the previous section that the function call form is always (some-function arguments):
((fn [x y] #{x y}) 1 2)
;=> #{1 2}
The second form to define functions allows for arity overloading of the invocations of
a function. Arity refers to the differences in the argument count that a function will
accept. Changing our previous simple set-creating function to accept either one or
two arguments would be represented as
(fn
([x] #{x})
([x y] #{x y}))
The difference from the previous form is that we can now have any number of argu-
ment/body pairs as long as the arity of the arguments differ. Naturally, the execution
of such a function for one argument would be
((fn
([x] #{x})
([x y] #{x y})) 42)
;=> #{42}
As you saw, arguments to functions are bound one-for-one to symbols during the func-
tion call, but there is a way for functions to accept a variable5 number of arguments:
((fn arity2 [x y] [x y]) 1 2 3)
;=> java.lang.IllegalArgumentException: Wrong number of args passed
Clearly, calling the arity2 function with three arguments won’t work. But what if we
wanted it to take any number of arguments? The way to denote variable arguments is
to use the & symbol followed by a symbol. Every symbol in the arguments list before
5 The implementation details of Clojure prevent the creation of functions with an arity larger than 20, but in
practice this should rarely, if ever, be an issue.
Download from Wow! eBook <www.wowebook.com>
Making things happen: functions
27
the & will still be bound one-for-one to the same number of arguments passed during
the function call. But any additional arguments will be aggregated in a sequence
bound to the symbol following the & symbol:
((fn arity2+ [x y & z] [x y z]) 1 2)
;=> [1 2 nil]
((fn arity2+ [x y & z] [x y z]) 1 2 3 4)
;=> [1 2 (3 4)]
((fn arity2+ [x y & z] [x y z]) 1)
;=> java.lang.IllegalArgumentException: Wrong number of args passed
Of course, arity2+ still requires at least two arguments. But this isn’t satisfactory, as it
quickly becomes clear that to write programs using only this form would be cumber-
some, repetitive, and overly verbose. Thankfully, Clojure provides another, more con-
venient form to create named functions.
2.3.3
Simplifying function definitions with def and defn
The def special form is a way to assign a symbolic name to a piece of Clojure data. Clo-
jure functions are first-class; they’re equal citizens with data, allowing assignment to
Vars, storage in collections, and as arguments to (or returned from) other functions.
This is different from programming languages where functions are functions and data
are data, and there’s a world of capability available to the latter that’s incongruous to
the former.
Therefore, in order to associate a name with our previous function using def,
we’d use
(def make-a-set
(fn
([x] #{x})
([x y] #{x y})))
And we could now call it in a more intuitive way:
(make-a-set 1)
;=> #{1}
(make-a-set 1 2)
;=> #{1 2}
There’s another way to define functions in Clojure using the defn macro. While cer-
tainly a much nicer way to define and consequently refer to functions by name, using
def as shown is still cumbersome to use. Instead, the simplest defn syntax is a conve-
nient and concise way to create named functions that looks similar to the original fn
form, and allow an additional documentation string:
(defn make-a-set
"Takes either one or two values and makes a set from them"
([x] #{x})
([x y] #{x y}))
The function can again be called the same as we saw before.
Download from Wow! eBook <www.wowebook.com>
28
CHAPTER 2 Drinking from the Clojure firehose
2.3.4
In-place functions with #()
Clojure provides a shorthand notation for creating an anonymous function using the
#() reader feature. In a nutshell, reader features are analogous to preprocessor direc-
tives in that they signify that some given form should be replaced with another at read
time. In the case of the #() form, it’s effectively replaced with the special form fn. In
fact, anywhere that it’s appropriate to use #(), it’s likewise appropriate for the fn spe-
cial form.
The #() form can also accept arguments that are implicitly declared through the
use of special symbols prefixed with %:
(def make-a-list_ #(list %))
(def make-a-list1 #(list %1))
(def make-a-list2 #(list %1 %2))
(def make-a-list3 #(list %1 %2 %3))
(def make-a-list3+ #(list %1 %2 %3 %&))
(make-a-list_ 1)
;=> (1)
(make-a-list3+ 1 2 3 4 5)
;=> (1 2 3 (4 5))
The %& argument in make-a-list3+ is used to specify the variable arguments as dis-
cussed previously.
2.4
Vars
Programmers are typically accustomed to dealing with variables and mutation. Clo-
jure’s closest analogy to the variable is the Var. A Var is named by a symbol and holds
a single value. Its value can be changed while the program is running, but this is best
reserved for the programmer making manual changes. A Var’s value can also be
shadowed by a thread local value, though this doesn’t change its original value or
root binding.
2.4.1
Declaring bindings using def
Using def is the most common way to create Vars in Clojure:
(def x 42)
Using def to associate the value 42 to the symbol x creates what’s known as a root
binding —a binding that’s the same across all threads, unless otherwise rebound rela-
tive to specific threads. By default, all threads start with the root binding, which is
their associated value in the absence of a thread-bound value.
The trivial case is that the symbol x is bound to the value 42. Because we used def
to create the Var’s root binding, we should observe that even other threads will view
the same root binding by default:
(.start (Thread. #(println "Answer: " x)))
; Answer: 42
Download from Wow! eBook <www.wowebook.com>
Locals, loops, and blocks
29
Vars don’t require a value; instead we can simply declare them and defer the responsi-
bility of binding their values to individual threads:6
(def y)
y
;=> java.lang.IllegalStateException: Var user/y is unbound.
Functions and vars theoretically provide all you need to implement any algorithm,
and some languages leave you with exactly these “atomic” constructs.
2.5
Locals, loops, and blocks
Clojure’s function and value binding capabilities provide a basis for much of what a
developer needs to start getting operational code, but a large part of the story is miss-
ing. Clojure also provides capabilities for creating local value bindings, looping con-
structs, and aggregating blocks of functionality.
2.5.1
Blocks
Use the do form when you have a series or block of expressions that need to be treated
as one. All the expressions will be evaluated, but only the last one will be returned:
(do
6
(+ 5 4)
3)
;=> 3
The expressions 6 and (+ 5 4) are perfectly valid and legal. The addition in (+ 5 4)
is even done, but the value is thrown away—only the final expression 3 is returned.
The middle bits of the do form are typically where the side-effects occur.
2.5.2
Locals
Clojure doesn’t have local variables, but it does have locals; they just can’t vary. Locals
are created and their scope defined using a let form, which starts with a vector that
defines the bindings, followed by any number of expressions that make up the body.
The vector starts with a binding form (usually just a symbol), which is the name of a
new local. This is followed by an expression whose value will be bound to this new
local for the remainder of the let form. You can continue pairing binding names and
expressions to create as many locals as you need. All of them will be available in the
body of the let:
(let [r 5
pi 3.1415
r-squared (* r r)]
(println "radius is" r)
(* pi r-squared))
6 We’ll talk more about per-thread bindings in chapter 11.
Download from Wow! eBook <www.wowebook.com>
30
CHAPTER 2 Drinking from the Clojure firehose
The body is sometimes described as an “implicit do” because it follows the same rules:
you may include any number of expressions and all will be evaluated, but only the
value of the last one is returned.
All of the binding forms in the previous example are simple symbols: r, pi, and r-
squared. More complex binding expressions can be used to pull apart expressions
that return collections. This feature is called destructuring: see section 2.9 for details.
Because they’re immutable, locals can’t be used to accumulate results; instead,
you’d use a high level function or loop/recur form.
2.5.3
Loops
The classic way to build a loop in a Lisp is a recursive call, and it’s in Clojure as well.
Using recursion sometimes requires thinking about your problem in a different way
than imperative languages encourage; but recursion from a tail position is in many
ways like a structured goto, and has more in common with an imperative loop than it
does with other kinds of recursion.
RECUR
Clojure has a special form called recur that’s specifically for tail recursion:
(defn print-down-from [x]
(when (pos? x)
(println x)
(recur (dec x))))
This is nearly identical to how you’d structure a while loop in an imperative language.
One significant difference is that the value of x isn’t decremented somewhere in the
body of the loop. Instead, a new value is calculated as a parameter to recur, which
immediately does two things: rebinds x to the new value and returns control to the top
of print-down-from.
If the function has multiple arguments, the recur call must as well, just as if you
were calling the function by name instead of using the recur special form. And just as
with a function call, the expressions in the recur are evaluated in order first and only
then bound to the function arguments simultaneously.
The previous example doesn’t concern itself with return values; it’s just about the
println side effects. Here’s a similar loop that builds up an accumulator and returns
the final result:
(defn sum-down-from [sum x]
(if (pos? x)
(recur (+ sum x) (dec x))
sum))
The only ways out of the function are recur, which isn’t really a way out, and sum. So
when x is no longer positive, the function will return the value of sum:
(sum-down-from 0 10)
;=> 55
Download from Wow! eBook <www.wowebook.com>
Locals, loops, and blocks
31
You may have noticed that the two preceding functions used different blocks: the first
when and the second if. You’ll often see one or the other used as a conditional, but
it’s not always immediately apparent why. In general, the reasons to use when are
No else-part is associated with the result of a conditional.
You require an implicit do in order to perform side-effects.
The reasons for the use of if would therefore be the inverse of those listed.
LOOP
Sometimes you want to loop back not to the top of the function, but to somewhere
inside. For example, in sum-down-from you might prefer that callers not have to pro-
vide an initial value for sum. To help, there’s a loop form that acts exactly like let but
provides a target for recur to jump to. It’s used like this:
(defn sum-down-from [initial-x]
(loop [sum 0, x initial-x]
(if (pos? x)
(recur (+ sum x) (dec x))
sum)))
Upon entering the loop form, the locals sum and x are initialized, just as they would
be for a let.
A recur always loops back to the closest enclosing loop or fn, so in this case it’ll go
to the loop. The loop locals are rebound to the values given in recur. The looping
and rebinding will continue until finally x is no longer positive. The return value of
the whole loop expression is sum, just as it was for the earlier function.
TAIL POSITION
Now that we’ve looked at a couple examples of how to use recur, we must discuss an
important restriction. The recur form can only appear in the tail position of a func-
tion or loop. So what’s a tail position? Succinctly, a form is in the tail position of an
expression when its value may be the return value of the whole expression. Consider
this function:
(defn absolute-value [x]
(if (pos? x)
x ; "then" clause
(- x))) ; "else" clause
It takes a single parameter and names it x. If x is already a positive number, then x is
returned; otherwise the opposite of x is returned.
The if form is in the function’s tail position because whatever it returns, the whole
function will return. The x in the “then” clause is also in a tail position of the function.
But the x in the “else” clause is not in the function’s tail position because the value of x
is passed to the - function, not returned directly. The else clause as a whole (- x) is in
a tail position.
If you try to use the recur form somewhere other than a tail position, Clojure will
remind you at compile time:
Download from Wow! eBook <www.wowebook.com>
32
CHAPTER 2 Drinking from the Clojure firehose
(fn [x] (recur x) (println x))
; java.lang.UnsupportedOperationException:
; Can only recur from tail position
You’ve seen how Clojure provides core functionality available to most popular pro-
gramming languages, albeit from a different bent. But in the next section, we’ll cover
the notion of quoting forms, which are in many ways unique to the Lisp family of lan-
guages and may seem alien to programmers coming from classically imperative and/
or object-oriented languages.
2.6
Preventing things from happening: quoting
Clojure has two quoting forms: quote and syntax-quote. Both are simple bits of syntax
you can put in front of a form in your program. They’re the primary ways for includ-
ing literal scalars and composites in your Clojure program without evaluating them as
code. But before quoting forms can make sense, you need a solid understanding of
how expressions are evaluated.
2.6.1
Evaluation
When a collection is evaluated, each of its contained items is evaluated first:7
(cons 1 [2 3])
If you enter this at the REPL, the form as a whole will be evaluated. In this specific
example, the function cons “constructs” a new sequence with its first argument in the
front of the sequence provided as its second. Because the form is a list, each of the
items will be evaluated first. A symbol, when evaluated, is resolved to a local, a Var, or a
Java class name. If a local or a Var, its value will be returned:
cons
;=> #<core$cons__3806 clojure.core$cons__3806@24442c76>
Literal scalar values evaluate to themselves—evaluating one just returns the same
thing:
1
;=> 1
The evaluation of another kind of collection, a vector, starts again by evaluating the
items it contains. Because they’re literal scalars, nothing much happens. Once that’s
done, evaluation of the vector can proceed. Vectors, like scalars and maps, evaluate to
themselves:
[2 3]
;=> [2 3]
Now that all the items of the original list have been evaluated (to a function, the
number 1, and the vector [2 3]), evaluation of the whole list can proceed. Lists are
7 ...unless it’s a list that starts with the name of a macro or special form. We’ll get to that later.
Download from Wow! eBook <www.wowebook.com>
Preventing things from happening: quoting
33
evaluated differently from vectors and maps: they call functions, or trigger special
forms, as shown:
(cons 1 [2 3])
;=> (1 2 3)
Whatever function was at the head of the list, cons in this case, is called with the
remaining items of the list as arguments.
2.6.2
Quoting
Using a special form looks like calling a function—a symbol as the first item of a list:
(quote tena)
Each special form has its own evaluation rules. The quote special form simply pre-
vents its argument from being evaluated at all. Though the symbol tena by itself might
evaluate to the value of a Var with the value 9, when it’s inside a quote form, it won’t:
(def tena 9)
(quote tena)
;=> tena
Instead, the whole form evaluates to just the symbol itself. This works for arbitrarily
complex arguments to quote: nested vectors, maps, even lists that would otherwise be
function calls, macro calls, or even more special forms. The whole thing is returned:
(quote (cons 1 [2 3]))
;=> (cons 1 [2 3])
There are a few reasons you might use the quote form, but by far the most common is
so that you can use a literal list as a data collection without having Clojure try to call a
function. We’ve been careful to use vectors in the examples so far in this section
because vectors are never themselves function calls. But if we wanted to use a list
instead, a naive attempt would fail:
(cons 1 (2 3))
; java.lang.ClassCastException:
; java.lang.Integer cannot be cast to clojure.lang.IFn
That’s Clojure telling us that an integer (the number 2 here) can’t be used as a func-
tion. So we have to prevent the form (2 3) from being treated like a function call—
exactly what quote is for:
(cons 1 (quote (2 3)))
;=> (1 2 3)
In other Lisps, this need is so common that they provide a shortcut: a single quote.
Although it’s used less in Clojure, it’s still provided. The previous example can also be
written as
(cons 1 '(2 3))
;=> (1 2 3)
Download from Wow! eBook <www.wowebook.com>
34
CHAPTER 2 Drinking from the Clojure firehose
And look at that: one less pair of parens—always welcome in a Lisp. Remember
though that quote affects all of its argument, not just the top level. So even though it
worked in the preceding examples to replace [] with '(), this may not always give you
the results you want:
[1 (+ 2 3)] ;=> [1 5]
'(1 (+ 2 3)) ;=> (1 (+ 2 3))
Finally, note that the empty list () already evaluates to itself; it doesn’t need to be
quoted. Quoting the empty list isn’t idiomatic Clojure.
SYNTAX-QUOTE
Like the quote, syntax-quote prevents its argument and subforms from being evalu-
ated. Unlike quote, it has a few extra features that make it ideal for constructing col-
lections to be used as code.
Syntax-quote is written as a single back-quote:
`(1 2 3)
;=> (1 2 3)
It doesn’t expand to a simple form like quote, but to whatever set of expressions is
required to support the following features.8
SYMBOL AUTO-QUALIFICATION
A symbol can begin with a namespace and a slash. These can be called qualified symbols:
clojure.core/map
clojure.set/union
i.just.made.this.up/quux
Syntax-quote will automatically qualify all unqualified symbols in its argument:
`map
;=> clojure.core/map
Ìnteger
;=> java.lang.Integer
`(map even? [1 2 3])
;=> (clojure.core/map clojure.core/even? [1 2 3])
If the symbol doesn’t name a Var or class that exists yet, syntax-quote will use the cur-
rent namespace:
ìs-always-right
;=> user/is-always-right
This behavior will come in handy in chapter 8, when we discuss macros.
2.6.3
Unquote
As you discovered, the quote special form prevents its argument, and all of its sub-
forms, from being evaluated. But there will come a time when you’ll want some of its
8 A future version of Clojure is likely to expand the back-quote to syntax-quote at read time and implement the
rest of syntax-quote’s features as a macro or special form.
Download from Wow! eBook <www.wowebook.com>
Preventing things from happening: quoting
35
constituent forms to be evaluated. The way to accomplish this feat is to use what’s
known as an unquote. An unquote is used to demarcate specific forms as requiring
evaluation by prefixing them with the symbol ~ within the body of a syntax-quote:
`(+ 10 (* 3 2))
;=> (clojure.core/+ 10 (clojure.core/* 3 2))
`(+ 10 ~(* 3 2))
;=> (clojure.core/+ 10 6)
What just happened? The final form uses an unquote to evaluate the subform (* 3
2), which of course performs a multiplication of 3 and 2, thus inserting the result into
the outermost syntax-quoted form. The unquote can be used to denote any Clojure
expression as requiring evaluation:
`(1 2 ~3)
;=> (1 2 3)
(let [x 2]
`(1 ~x 3))
;=> (1 2 3)
`(1 ~(2 3))
;=> java.lang.ClassCastException: java.lang.Integer
Whoops! By using the unquote, we’ve told Clojure that the marked form should be
evaluated. But the marked form here is (2 3), and what happens when Clojure
encounters an expression like this? It attempts to evaluate it as a function! Therefore,
care needs to be taken with unquote to ensure that the form requiring evaluation is of
the form that you expect. The more appropriate way to perform the previous task
would thus be
(let [x '(2 3)] `(1 ~x))
;=> (1 (2 3))
This provides a level of indirection such that the expression being evaluated is no lon-
ger (2 3) but x. But this new way breaks the pattern of the previous examples that
returned a list of (1 2 3).
2.6.4
Unquote-splicing
Clojure provides a handy feature to solve exactly the problem posed earlier. A variant
of unquote called unquote-splicing works similarly to unquote, but a little differently:
(let [x '(2 3)] `(1 ~@x))
;=> (1 2 3)
Note the @ in ~@, which tells Clojure to unpack the sequence x, splicing it into the
resulting list rather than inserting it as a nested list.
Download from Wow! eBook <www.wowebook.com>
36
CHAPTER 2 Drinking from the Clojure firehose
2.6.5
Auto-gensym
Sometimes you need an unqualified symbol, such as for a parameter or let local
name. The easiest way to do this inside a syntax-quote is to append a # to the symbol
name. This will cause Clojure to generate a new unqualified symbol:
`potion#
;=> potion__211__auto__
Sometimes even this isn’t enough, either because you need to refer to the same sym-
bol in multiple syntax-quotes or because you want to capture a particular unqualified
symbol.
Until this point, we’ve covered many of the basic features making Clojure a unique
flavor of Lisp. But one of the main goals that Clojure excels at meeting is that of
interoperability with a host language and runtime, namely Java and the Java Virtual
Machine.
2.7
Leveraging Java via interop
Clojure is symbiotic with its host,9 providing its rich and powerful features, while Java
provides an object model, libraries, and runtime support. In this section, we’ll take a
brief look at how Clojure allows you to access Java classes and class members, and how
you can create instances and access their members.
2.7.1
Accessing static class members
Clojure provides powerful mechanisms for accessing, creating, and mutating Java
classes and instances. The trivial case is accessing static class properties:
java.util.Locale/JAPAN
;=> #<Locale ja_JP>
Idiomatic Clojure prefers that you access static class members using a syntax like
accessing a namespace-qualified Var:
(Math/sqrt 9)
;=> 3.0
The preceding call is to the java.lang.Math#sqrt static method.
2.7.2
Creating Java class instances
Creating Java class instances is likewise a trivial matter with Clojure. The new special
form closely mirrors the Java model:
(new java.util.HashMap {"foo" 42 "bar" 9 "baz" "quux"})
;=> #<HashMap {baz=quux, foo=42, bar=9}>
The second, more succinct, Clojure form to create instances is actually the idiomatic
form:
9 We’ll focus on the Java Virtual Machine throughout this book, but Clojure has also been hosted on the .NET
Common Language Runtime (CLR) and JavaScript (http://clojurescript.n01se.net/repl/).
Download from Wow! eBook <www.wowebook.com>
Leveraging Java via interop
37
(java.util.HashMap. {"foo" 42 "bar" 9 "baz" "quux"})
;=> #<HashMap {baz=quux, foo=42, bar=9}>
As you can see, the class name was followed by a dot in order to signify a constructor
call.
2.7.3
Accessing Java instance members with the . operator
To access instance properties, precede the property or method name with a dot:
(.x (java.awt.Point. 10 20))
;=> 10
This returns the value of the field x from the Point instance given.
To access instance methods, the dot form allows an additional argument to be
passed to the method:
(.divide (java.math.BigDecimal. "42") 2M)
;=> 21M
The preceding example calls the #divide method on the class BigDecimal.
2.7.4
Setting Java instance properties
In the absence of mutators in the form setXXX, Java instance properties can be set via
the set! function:
(let [origin (java.awt.Point. 0 0)]
(set! (.x origin) 15)
(str origin))
;=> "java.awt.Point[x=15,y=0]"
The first argument to set! is the instance member access form.
2.7.5
The .. macro
When working with Java, it’s common practice to chain together a sequence of
method calls on the return type of the previous method call:
new java.util.Date().toString().endsWith("2010") /* Java code */
Using Clojure’s dot special form, the following code is equivalent:
(.endsWith (.toString (java.util.Date.)) "2010") ; Clojure code
;=> true
Though correct, the preceding code is difficult to read and will only become more so
when we lengthen the chain of method calls. To combat this, Clojure provides the ..
macro, which can simplify the call chain as follows:
(.. (java.util.Date.) toString (endsWith "2010"))
The preceding .. call closely follows the equivalent Java code and is much easier to
read. Bear in mind, you might not see .. used often in Clojure code found in the wild
outside of the context of macro definitions. Instead, Clojure provides the -> and ->>
macros, which can be used similarly to the .. macro but are also useful in non-interop
Download from Wow! eBook <www.wowebook.com>
38
CHAPTER 2 Drinking from the Clojure firehose
situations, thus making them the preferred method call facilities in most cases. The ->
and ->> macros are covered in more depth in the introduction to chapter 8.
2.7.6
The doto macro
When working with Java, it’s also common to initialize a fresh instance by calling a set
of mutators:
java.util.HashMap props = new java.util.HashMap(); /* More java code. */
props.put("HOME", "/home/me"); /* Sorry. */
props.put("SRC", "src");
props.put("BIN", "classes");
But using this method is overly verbose and can be streamlined using the doto macro,
which takes the form
(doto (java.util.HashMap.)
(.put "HOME" "/home/me")
(.put "SRC" "src")
(.put "BIN" "classes"))
;=> #<HashMap {HOME=/home/me, BIN=classes, SRC=src}>
Though these Java and Clojure comparisons are useful, it shouldn’t be assumed that
their compiled structures are the same.
2.7.7
Defining classes
Clojure provides the reify and deftype macros as possible ways to create realizations
of Java interfaces, but we’ll defer covering them until chapter 9. Additionally, Clojure
provides a macro named proxy that can be used to implement interfaces and extend
base classes on the fly. Similarly, using the gen-class macro, you can generate statically
named classes. More details about proxy and gen-class are available in chapter 10.
2.8
Exceptional circumstances
We’ll now talk briefly about Clojure’s facilities for handling exceptions. Like Java, Clo-
jure provides a couple of forms for throwing and catching runtime exceptions:
namely throw and catch, respectively.
2.8.1
A little pitch and catch
The mechanism to throw an exception is fairly straightforward:
(throw (Exception. "I done throwed"))
;=> java.lang.Exception: I done throwed
The syntax for catching exceptions in Clojure is similar to that of Java:
(defn throw-catch [f]
[(try
(f)
(catch ArithmeticException e "No dividing by zero!")
(catch Exception e (str "You are so bad " (.getMessage e)))
Download from Wow! eBook <www.wowebook.com>
Namespaces
39
(finally (println "returning... ")))])
(throw-catch #(/ 10 5))
; returning...
;=> [2]
(throw-catch #(/ 10 0))
; returning...
;=> ["No dividing by zero!"]
(throw-catch #(throw (Exception. "foo")))
; returning...
;=> ["You are so bad foo"]
The major difference between the way that Java handles exceptions compared to Clo-
jure is that Clojure doesn’t adhere to checked exception requirements. In the next,
final section of our introduction to Clojure, we present namespaces, which might look
vaguely familiar if you’re familiar with Java or Common Lisp.
2.9
Namespaces
Clojure’s namespaces provide a way to bundle related functions, macros, and values.
In this section, we’ll briefly talk about how to create namespaces and how to reference
and use things from other namespaces.
2.9.1
Creating namespaces using ns
To create a new namespace, you can use the ns macro:
(ns joy.ch2)
Whereupon your REPL prompt will now display as:
joy.ch2=>
This prompt shows that you’re working within the context of the joy.ch2 namespace.
Clojure also provides a Var *ns* that holds the value of the current namespace. Any
Var created will be a member of the current namespace:
(defn hello [] (println "Hello Cleveland!"))
(defn report-ns [] (str "The current namespace is " *ns*))
(report-ns)
;=> "The current namespace is joy.ch2"
Entering a symbol within a namespace will cause Clojure to attempt to look up its
value within the current namespace:
hello
;=> #<ch2$hello joy.ch2$hello@2af8f5>
You can create new namespaces at any time:
(ns joy.another)
Again, you’ll notice that your prompt has changed, indicating that the new context is
joy.another. Attempting to run report-ns will no longer work:
Download from Wow! eBook <www.wowebook.com>
40
CHAPTER 2 Drinking from the Clojure firehose
(report-ns)
; java.lang.Exception:
; Unable to resolve symbol: report-ns in this context
This is because report-ns exists in the joy.ch1 namespace and is only accessible via
its fully qualified name joy.ch2/report-ns. But this will only work for namespaces
created locally or those previously loaded, which we’ll discuss next.
2.9.2
Loading other namespaces with :require
Creating a namespace is straightforward, but how do you load namespaces? Clojure
provides a convenience directive :require to take care of this task. Observe the
following:
(ns joy.req
(:require clojure.set))
(clojure.set/intersection #{1 2 3} #{3 4 5})
;=> #{3}
Using :require indicates that you want the clojure.set namespace loaded, but you
don’t want the mappings of symbols to functions in the joy.req namespace. You can
also use the :as directive to create an additional alias to clojure.set:
(ns joy.req-alias
(:require [clojure.set :as s]))
(s/intersection #{1 2 3} #{3 4 5})
;=> #{3}
The qualified namespace form looks the same as a call to a static class method. The
difference is that a namespace symbol can only be used as a qualifier, whereas a class
symbol can also be referenced independently:
clojure.set
; java.lang.ClassNotFoundException: clojure.set
java.lang.Object
;=> java.lang.Object
The vagaries of namespace mappings from symbols to Vars both qualified and unqual-
ified have the potential for confusion between class names and static methods in the
beginning, but the differences will begin to feel natural as you progress. In addition,
idiomatic Clojure code will tend to use my.Class and my.ns for naming classes and
namespaces respectively, to help eliminate potential confusion.
2.9.3
Loading and creating mappings with :use
Sometimes you’ll want to create mappings from Vars in another namespace to names
in your own, in order to avoid calling each function or macro with the qualifying
namespace symbol. To create these unqualified mappings, Clojure provides the :use
directive:
(ns joy.use-ex
(:use [clojure.string :only [capitalize]]))
Download from Wow! eBook <www.wowebook.com>
Namespaces
41
(map capitalize ["kilgore" "trout"])
;=> ("Kilgore" "Trout")
The :use directive indicates that only the function capitalize should be mapped in
the namespace joy.use-ex. Specifying the Vars that you’d like explicit mappings for
is good practice in Clojure, as it avoids creating many unnecessary names within a
namespace. Unnecessary names increase the odds of names clashes, which you’ll see
next. A similar directive to :use for managing precise mappings is :exclude
(ns joy.exclusion
(:use [clojure.string :exclude [capitalize]]))
; WARNING: replace already refers to: #'clojure.core/replace in namespace:
; joy.exclusion, being replaced by: #'clojure.string/replace
; WARNING: reverse already refers to: #'clojure.core/reverse in namespace:
; joy.exclusion, being replaced by: #'clojure.string/reverse
(map capitalize ["kilgore" "trout"])
; java.lang.Exception: Unable to resolve symbol: capitalize in this context
The :exclude directive indicates that we wanted to map names for all of clojure.
string’s Vars except for capitalize. Indeed, any attempt to use capitalize directly
throws an exception. But it’s still accessible via clojure.string/capitalize. The rea-
son for this accessibility is because :use implicitly performs a :require directive in
addition to creating mappings. As you might’ve noticed, the creation of the joy.
exclusion namespace signaled two warnings. The reason was that the clojure.
string namespace defines two functions reverse and replace that are already
defined in the clojure.core namespace—which was already loaded by using ns.
Therefore, when either of those functions are used, the last Var definition wins:
(reverse "abc")
;=> "cba"
(clojure.core/reverse "abc")
(\c \b \a)
The clojure.string version of reverse takes precedence over the clojure.core ver-
sion, which may or may not be what we wanted. You should always strive to eliminate
the warnings that Clojure presents in these cases. The most obvious strategy for resolv-
ing these particular warnings would be to use the :require directive to create a
namespace alias with :as as we showed in the previous section.
2.9.4
Creating mappings with :refer
Clojure also provides a :refer directive that works almost exactly like :use except
that it only creates mappings for libraries that have already been loaded:
(ns joy.yet-another
(:refer joy.ch1))
(report-ns)
;=> "The current namespace is #<Namespace joy.yet-another>"
Download from Wow! eBook <www.wowebook.com>
42
CHAPTER 2 Drinking from the Clojure firehose
The use of :refer in this way creates a mapping from the name report-ns to the
actual function located in the namespace joy.ch2 so that the function can be called
normally. You could also set an alias for the same function using the :rename keyword
taking a map, as shown:
(ns joy.yet-another
(:refer joy.ch1 :rename {hello hi}))
(hi)
; Hello Cleveland!
Any namespaces referenced must already be loaded implicitly by being previously
defined or by being one of Clojure’s core namespaces, or explicitly loaded through the
use of :require. It should be noted that :rename also works with the :use directive.
2.9.5
Loading Java classes with :import
To use unqualified Java classes within any given namespace, they should be imported
via the :import directive, as shown:
(ns joy.java
(:import [java.util HashMap]
[java.util.concurrent.atomic AtomicLong]))
(HashMap. {"happy?" true})
;=> #<HashMap {happy?=true}>
(AtomicLong. 42)
;=> 42
As a reminder, any classes in the Java java.lang package are automatically imported
when namespaces are created. We’ll discuss namespaces in more detail in sections 9.1
and 10.2.
2.10
Summary
We named this chapter “Drinking from the Clojure firehose”—and you’ve made it
through! How does it feel? We’ve only provided an overview of the topics needed to
move on to the following chapters instead of a full-featured language tutorial. Don’t
worry if you don’t fully grasp the entirety of Clojure the programming language;
understanding will come as you work your way through the book.
In the next chapter, we’ll take a step back and delve into some topics that can’t be
easily categorized, but that deserve attention because of their ubiquity. It’ll be short
and sweet and give you a chance to take a breath before moving into the deeper dis-
cussions on Clojure later in the book.
Download from Wow! eBook <www.wowebook.com>
Dipping our toes
in the pool
This chapter covers
Truthiness
Nil punning
Destructuring
Use the REPL to experiment
Deeper and broader topics will be covered in later chapters, but now’s a good time
to pick through an eclectic selection of smaller topics. The topics covered in this
chapter stand alone but are important. Covering them now will be a fun way to start
digging into practical matters of how to use Clojure.
We’ve covered a lot of conceptual ground in the previous chapter and built our
Clojure lexicon. In this chapter, we’ll take a bit of a detour into some fundamental
underpinnings driving idiomatic Clojure source code. First we’ll explore Clojure’s
straightforward notions of Truthiness,1 or the distinctions between values
1 As a deviation from the definition coined by Stephen Colbert in his television show The Colbert Report. Ours
isn’t about matters of gut feeling but rather about matters of Clojure’s logical truth ideal.
43
Download from Wow! eBook <www.wowebook.com>
44
CHAPTER 3 Dipping our toes in the pool
considered logical true and those considered logical false. Much of idiomatic Clojure
code is built with matters of Truthiness in mind, and we’ll discuss Clojure’s extremely
simple rules. After this we’ll then move on to the notion of nil punning, or treating an
empty sequence as nil. Those of you coming from a background in Lisp may recog-
nize the term, but Clojure handles nil punning differently. We’ll discuss the idioms
related to nil punning in Clojure and their rationale. We’ll then cover destructuring—
a powerful mechanism for pulling apart collection types and binding their constituent
parts as individual values. Using destructuring within your own code can often lead to
extremely concise and elegant solutions, and we’ll provide some examples to illustrate
this. Finally, we’ll sit down and pair-program together to gain an appreciation for the
power of Clojure’s Read-Eval-Print Loop (REPL).
3.1
Truthiness
Truthfulness may be an important virtue, but it doesn’t come up much in program-
ming. On the other hand, Truthiness, or the matter of logical truth values in Clojure, is
critical.
Clojure has one Boolean context: the test expression of the if form. Other forms
that expect Booleans—and, or, when, and so forth—are macros built on top of if. It’s
here that Truthiness matters.
3.1.1
What’s truth?
Every value looks like true to if, except for false and nil. That means that values
which some languages treat as false—zero-length strings, empty lists, the number zero,
and so on—are all treated as true in Clojure:
(if true :truthy :falsey) ;=> :truthy
(if [] :truthy :falsey) ;=> :truthy
(if nil :truthy :falsey) ;=> :falsey
(if false :truthy :falsey) ;=> :falsey
This may feel uncomfortable to you, depending on your background. But because
branches in a program’s logic are already one of the most likely places for complexity
and bugs, Clojure has opted for a simple rule. There’s no need to check a class’s defi-
nition to see if it acts like “false” when you think it should (as is sometimes required in
Python, for example). Every object is “true” all the time, unless it’s nil or false.
3.1.2
Don’t create Boolean objects
It’s possible to create an object that looks a lot like, but isn’t actually, false.
Java has left a landmine for you here, so take a moment to look at it so that you can
step past it gingerly and get on with your life:
(def evil-false (Boolean. "false")) ; NEVER do this
This creates a new instance of Boolean—and that’s already wrong! Because there are
only two possible values of Boolean, an instance of each has already been made for
Download from Wow! eBook <www.wowebook.com>
Nil pun with care
45
you—they’re named true and false.2 But here you’ve gone and done it anyway,
created a new instance of Boolean and stored it in a Var named evil-false. It looks
like false:
evil-false
;=> false
Sometimes it even acts like false:
(= false evil-false)
;=> true
But once it gains your trust, it’ll show you just how wicked it is by acting like true:
(if evil-false :truthy :falsey)
;=> :truthy
Java’s own documentation warns against the creation of this evil thing, and now you’ve
been warned again. If you just want to parse a string, use the Boolean class’s static
valueOf method instead of its constructor. This is the right way:
(if (Boolean/valueOf "false") :truthy :falsey)
;=> :falsey
3.1.3
nil versus false
Rarely do you need to differentiate between the two false values, but if you do, you can
use nil? and false?:
(when (nil? nil) "Actually nil, not false")
;=> "Actually nil, not false"
Keeping in mind the basic rule that everything in Clojure is truthy unless it’s false or
nil is an astonishingly powerful concept, allowing for elegant solutions. Often pro-
gramming languages have complicated semantics for Truthiness, but Clojure manages
to avoid those matters nicely. You’ll see this simplicity leveraged throughout this book
and in all examples of idiomatic Clojure source code.
Building on that theme, we’ll now discuss the matter of nil punning, which may or
may not surprise you given your background.
3.2
Nil pun with care
Because empty collections act like true in Boolean contexts, we need an idiom for
testing whether there’s anything in a collection to process. Thankfully, Clojure pro-
vides just such a technique:
(seq [1 2 3])
;=> (1 2 3)
(seq [])
;=> nil
2 Clojure’s true and false instances are the same as Java’s Boolean/TRUE and Boolean/FALSE, respectively.
Download from Wow! eBook <www.wowebook.com>
46
CHAPTER 3 Dipping our toes in the pool
The seq function returns a sequence view of a collection, or nil if the collection is
empty. In a language like Common Lisp, an empty list acts as a false value and can be
used as a pun (a term with the same behavior) for such in determining a looping ter-
mination. As you saw in section 2.3, Clojure’s empty sequences are instead truthy, and
therefore to use one as a pun for falsity will lead to heartache and despair. One solu-
tion that might come to mind is to use empty? in the test, leading to the awkward
phrase (when-not (empty? s) ...). Though it would work, this isn’t idiomatic. A
better solution would be to use seq as a termination condition, as in the following
function print-seq:
(defn print-seq [s]
(when (seq s)
(prn (first s))
(recur (rest s))))
(print-seq [1 2])
; 1
; 2
;=> nil
(print-seq [])
;=> nil
There are a number of points to take away from this example. First, the use of seq as a
terminating condition is the idiomatic way to test whether a sequence is empty. If we
tested just s instead of (seq s), then the terminating condition wouldn’t occur even
for empty collections, leading to an infinite loop.
PREFER DOSEQ An important point not mentioned is that it would be best to
use doseq in this case, but that wouldn’t allow us to illustrate our overarching
points: the Clojure forms named with do at the start (doseq, dotimes, do, and
so on) are intended for side-effects in their bodies and generally return nil as
their results.
Second, rest is used to consume the sequence on the recursive call, which can return
a sequence that’s either empty or not empty (has elements). Clojure also provides a
next function that returns a seq of the rest, or (seq (rest s)), and thus never returns
an empty sequence, but nil instead. But rest is appropriate here because we’re using
seq explicitly in each subsequent iteration. Finally, print-seq is a template for most
functions in Clojure, in that it shows that we should generally not assume seq has been
called on our collection arguments, but instead call seq within the function itself and
process based on its result. Using this approach fosters a more generic handling of col-
lections, a topic that we explore in great detail in chapter 5. In the meantime, it’s
important to keep in mind the difference between empty collections and false values;
otherwise your attempts at nil punning may cause groans all around.
To top off our trifecta of core Clojure concepts, we next explore the most powerful
of the three—destructuring. You’ll see just how powerful this mini-language within
Clojure can be toward developing elegant and often beautiful solutions.
Download from Wow! eBook <www.wowebook.com>
Destructuring
47
3.3
Destructuring
In the previous section, we briefly described Clojure’s destructuring facility as a mini-
language embedded within Clojure. Destructuring allows us to positionally bind locals
based on an expected form for a composite data structure. In this section, we’ll
explore how destructuring can be used to pull apart composite structures into bind-
ings through the lens of a simple rolodex example project.
PATTERN MATCHING Destructuring is loosely related to pattern matching
found in Haskell, KRC, or Scala, but much more limited in scope. For more
full-featured pattern matching in Clojure, consider using http://
github.com/dcolthorp/matchure, which may in the future be included in contrib as clojure.core.match.
3.3.1
Your assignment, should you choose to accept it
You’ve heard that the rolodex project has been overdue, but now every developer
assigned to it is out sick. The QA team is ready to go, but one function is still missing
and it’s a show-stopper. You’re told to drop everything and write the function ASAP.
The design? Take a vector of length 3 that represents a person’s first, middle, and
last names and return a string that will sort in the normal way, like “Steele, Guy Lewis”.
What are you waiting for? Why aren’t you done yet?!?!
(def guys-whole-name ["Guy" "Lewis" "Steele"])
(str (nth guys-whole-name 2) ", "
(nth guys-whole-name 0) " "
(nth guys-whole-name 1)))
;=> "Steele, Guy Lewis"
Alas, by the time you’ve finished typing guys-whole-name for the fourth time, it’s too
late. The customers have cancelled their orders, and the whole department is bound
to be downsized.
If only you’d known about destructuring.
Okay, so you’re not likely to lose your job because your function is twice as many
lines as it needs to be, but still that’s a lot of code repeated in a pretty small function.
And using index numbers instead of named locals makes the purpose of the function
more obscure than necessary.
Destructuring solves both these problems by allowing you to place a collection of
names in a binding form where normally you’d put just a single name. One kind of
binding form is the list of parameters given in a function definition.
3.3.2
Destructuring with a vector
So let’s try that again, but use destructuring with let to create more convenient locals
for the parts of Guy’s name:
(let [[f-name m-name l-name] guys-whole-name]
(str l-name ", " f-name " " m-name))
Download from Wow! eBook <www.wowebook.com>
48
CHAPTER 3 Dipping our toes in the pool
Positional destructuring
This positional destructuring doesn’t work on maps and sets because they’re not
logically3 aligned sequentially. Thankfully, positional destructuring will work with
Java’s java.util.regex.Matcher and anything implementing the CharSequence
and java.util.RandomAccess interfaces.
This is the simplest form of destructuring, where you want to pick apart a sequential
thing (a vector of strings in this case, though a list or other sequential collection
would work as well), giving each item a name.3
We don’t need it here, but we can also use an ampersand in a destructuring vector
to indicate that any remaining values of the input should be collected into a (possibly
lazy) seq:
(let [[a b c & more] (range 10)]
(println "a b c are:" a b c)
(println "more is:" more))
; a b c are: 0 1 2
; more is: (3 4 5 6 7 8 9)
;=> nil
Here the locals a, b, and c are created and bound to the first three values of the range.
Because the next symbol is an ampersand, the remaining values are made available as
a seq bound to more. The name more is pretty common for this purpose, but isn’t spe-
cial—you’ll often see etc or xs instead, or some other name that makes sense in a par-
ticular context.
The final feature of vector destructuring is :as, which can be used to bind a local
to the entire collection. It must be placed after the & local, if there is one, at the end of
the destructuring vector:
(let [range-vec (vec (range 10))
[a b c & more :as all] range-vec]
(println "a b c are:" a b c)
(println "more is:" more)
(println "all is:" all))
; a b c are: 0 1 2
; more is: (3 4 5 6 7 8 9)
; all is: [0 1 2 3 4 5 6 7 8 9]
;=> nil
We made range-vec a vector in this example, and the directive :as binds the input
collection as-is, entirely unmolested, so that the vector stays a vector. This is in contrast
to &, which bound more to a seq, not a vector.
3 Technically, positional destructuring might make sense with sorted sets and maps, but alas it doesn’t operate
as such.
Download from Wow! eBook <www.wowebook.com>
Destructuring
49
3.3.3
Destructuring with a map
Perhaps passing a name as a three-part vector wasn’t a good idea in the first place. It
might be better stored in a map:
(def guys-name-map
{:f-name "Guy" :m-name "Lewis" :l-name "Steele"})
But now we can’t use a vector to pick it apart effectively. Instead, we use a map:
(let [{f-name :f-name, m-name :m-name, l-name :l-name} guys-name-map]
(str l-name ", " f-name " " m-name))
A couple things about this example may jump out at you. One might be that it still
seems repetitive—we’ll get to that in a moment.
Another might be that it looks a bit unexpected to have the keywords like :f-name
on the right-hand side of each pair even though the input map had keywords on the
left. There are a couple reasons for that. The first is to help keep the pattern of the
name on the left getting the value specified by the thing on the right. That is, the new
local f-name gets the value looked up in the map by the key :f-name, just as the whole
map gets its value from guys-name-map in the earlier def form.
The second reason is because it allows us to conjure up other destructuring fea-
tures by using forms that would otherwise make no sense. Because the item on the left
of each pair will be a new local name, it must be a symbol or possibly a nested destruc-
turing form. But one thing it can’t be is a keyword, unless the keyword is a specially
supported feature such as :keys, :strs, :syms, :as, and :or.
We’ll discuss the :keys feature first because it nicely handles the repetitiveness we
mentioned earlier. It allows us to rewrite our solution like this:
(let [{:keys [f-name m-name l-name]} guys-name-map]
(str l-name ", " f-name " " m-name))
So by using :keys instead of a binding form, we’re telling Clojure that the next form
will be a vector of names that it should convert to keywords such as :f-name in order
to look up their values in the input map. Similarly, if we had used :strs, Clojure
would be looking for items in the map with string keys such as "f-name", and :syms
would indicate symbol keys.
The directives :keys, :strs, :syms, and regular named bindings can appear in
any combination and in any order. But sometimes you’ll want to get at the original
map—in other words, the keys that you didn’t name individually by any of the meth-
ods just described. For that, you want :as, which works just like it does with vector
destructuring:
(let [{f-name :f-name, :as whole-name} guys-name-map]
whole-name)
;=> {:f-name "Guy", :m-name "Lewis", :l-name "Steele"}
If the destructuring map looks up a key that’s not in the source map, it’s normally
bound to nil, but you can provide different defaults with :or:
Download from Wow! eBook <www.wowebook.com>
50
CHAPTER 3 Dipping our toes in the pool
(let [{:keys [title f-name m-name l-name], :or {title "Mr."}} guys-name-map]
(println title f-name m-name l-name))
; Mr. Guy Lewis Steele
;=> nil
ASSOCIATIVE DESTRUCTURING
One final technique worth mentioning is associative destructuring. Using a map to
define a number of destructure bindings isn’t limited to maps. We can also destruc-
ture a vector by providing a map declaring the local name as indices into them, as
shown:
(let [{first-thing 0, last-thing 3} [1 2 3 4]]
[first-thing last-thing])
;=> [1 4]
We’ll explore associative destructuring later in section 6.1 when we discuss Clojure’s
support for named structures. You’ve seen the shapes that destructuring takes within
the let form, but you’re not limited to that exclusively, as we’ll explore next.
3.3.4
Destructuring in function parameters
All the preceding examples use let to do their destructuring, but exactly the same
features are available in function parameters. Each function parameter can destruc-
ture a map or sequence:
(defn print-last-name [{:keys [l-name]}]
(println l-name))
(print-last-name guys-name-map)
; Steele
;=> nil
Note that function arguments can include an ampersand as well, but this isn’t the
same as destructuring. Instead, that’s part of their general support for multiple func-
tion bodies, each with its own number of parameters.
3.3.5
Destructuring versus accessor methods
In many object-oriented languages, you might create new classes to manage your
application data objects, each with its own set of getter and setter methods. It’s idiom-
atic in Clojure to instead build your application objects by composing maps and vec-
tors as necessary. This makes destructuring natural and straightforward. So anytime
you find that you’re calling nth on the same collection a few times, or looking up con-
stants in a map, or using first or next, consider using destructuring instead.
Now that we’ve made it through the cursory introduction to Clojure, let’s take
some time to pair-program (Williams 2002). In the next section, we’ll take many of
the bare necessities that you’ve just learned and walk through the creation of a couple
interesting functions for drawing pretty pictures within Clojure’s REPL.
Download from Wow! eBook <www.wowebook.com>
Using the REPL to experiment
51
3.4
Using the REPL to experiment
Most software development projects include a stage where you’re not sure what needs
to happen next. Perhaps you need to use a library or part of a library you’ve never
touched before. Or perhaps you know what your input to a particular function will be,
and what the output should be, but you aren’t sure how to get from one to other. In
more static languages, this can be time-consuming and frustrating; but by leveraging
the power of the Clojure REPL, the interactive command prompt, it can actually be fun.
3.4.1
Experimenting with seqs
Say someone suggests to you that coloring every pixel of a canvas with the xor of its x
and y coordinates might produce an interesting image. It shouldn’t be too hard, so
you can jump right in. You’ll need to perform an operation on every x and y in a pair
of ranges. Do you know how range works?
(range 5)
;=> (0 1 2 3 4)
That should do nicely for one coordinate. To nest seqs, for often does the trick. But
again, rather than writing code and waiting until you have enough to warrant compil-
ing and testing, you can just try it:
(for [x (range 2) y (range 2)] [x y])
;=> ([0 0] [0 1] [1 0] [1 1])
There are the coordinates that will form your input. Now you need to xor them:
(xor 1 2)
;=> java.lang.Exception: Unable to resolve symbol: xor in this context
Bother—no function named xor. Fortunately, Clojure provides find-doc, which
searches not just function names but also their doc strings for the given term:
(find-doc "xor")
; -------------------------
; clojure.core/bit-xor
; ([x y])
; Bitwise exclusive or
;=> nil
So the function you need is called bit-xor:
(bit-xor 1 2)
;=> 3
Perfect! Now you want to adjust your earlier for form to return the bit-xor along
with the x and y. The easiest way to do this will depend on what tool is hosting your
REPL. In many, you can just press the up-arrow key on your keyboard a couple of times
to bring back the earlier for form. You’re not going to want to retype things to make
minor adjustments, so take a moment right now to figure out a method you like that
will allow you to make a tweak like this by inserting the bit-xor call:
Download from Wow! eBook <www.wowebook.com>
52
CHAPTER 3 Dipping our toes in the pool
(for [x (range 2) y (range 2)] [x y (bit-xor x y)])
;=> ([0 0 0] [0 1 1] [1 0 1] [1 1 0])
That looks about right. Now you’re about to shift gears to pursue the graphics side of
this problem, so tuck that bit of code away in a function so it’ll be easy to use later:
(defn xors [max-x max-y] (for [x (range max-x) y (range max-y)] [x y (bit-
xor x y)]))
(xors 2 2)
;=> ([0 0 0] [0 1 1] [1 0 1] [1 1 0])
You might even save that into a .clj file somewhere, if you haven’t already.
3.4.2
Experimenting with graphics
Clojure’s REPL isn’t just for playing around; it’s also great for experimenting with Java
libraries. We believe that there’s no better environment for exploring a Java API than
Clojure’s REPL. To illustrate, poke around with java.awt, starting with a Frame:
(def frame (java.awt.Frame.))
;=> #'user/frame
That should’ve created a Frame, but no window appeared. Did it work at all?
frame
;=> #<Frame java.awt.Frame[frame0,0,22,0x0,invalid,hidden,...]>
Well, you have a Frame object, but perhaps the reason you can’t see it is hinted at by
the word hidden in the #<Frame...> printout. Perhaps the Frame has a method you
need to call to make it visible. One way to find out would be to check the Javadoc of
the object, but because you’re at the REPL already, let’s try something else. You’ve
already seen how the for macro works, so maybe you can check a class for which
methods it has to see whether one that you can use is available:
(for [method (seq (.getMethods java.awt.Frame))
:let [method-name (.getName method)]
:when (re-find #"Vis" method-name)]
method-name)
;=> ("setVisible" "isVisible")
The for macro takes a :let flag and bindings vector that works similarly to the let
special form that you use to bind the local method-name to the result of calling the
method .getName on each method in turn. The :when is used to limit the elements
used in its body to only those that return a truthy value in the expression after the
directive. Using these directives allows you to iterate through the methods and build a
seq of those whose names match a regular expression #"Vis". We’ll cover Clojure’s
regular expression syntax in section 3.5.
THE CONTRIB FUNCTION SHOW The clojure-contrib library also has a function
show in the clojure.contrib.repl-utils namespace that allows for more
useful printouts of class members than we show using for.
Your query returned two potential methods, so try out each of them:
Download from Wow! eBook <www.wowebook.com>
Using the REPL to experiment
53
(.isVisible frame)
;=> false
That’s false, as you might’ve suspected. Will setting it to true make any difference?
(.setVisible frame true)
;=> nil
It did, but it’s so tiny! Not to worry, as a Frame class also has a .setSize method that
you can use:
(.setSize frame (java.awt.Dimension. 200 200))
;=> nil
And up pops a blank window for you to draw on. At this point, we’ll guide you
through the rest of this section, but keep in mind that Java’s official API might be of
interest should you choose to extend the example program.
THE JAVADOC FUNCTION As of Clojure 1.2, a javadoc function is automati-
cally available at the REPL to query and view official API documentation:
(javadoc frame)
This should return a string corresponding to a URL and open a browser win-
dow for just the right page of documentation. Prior to Clojure 1.2, this func-
tion was in clojure.contrib.repl-utils.
What you need to draw into your Frame is its graphics context, which can be fetched
as shown:
(def gfx (.getGraphics frame))
;=> #'user/gfx
Then, to actually draw, you can try out the fillRect method of that graphics context.
If you’re trying this yourself, make sure the blank window is positioned so that it’s
unobscured while you’re typing into your REPL:
(.fillRect gfx 100 100 50 75)
And just like that, you’re drawing on the screen interactively. You should see a single
black rectangle in the formerly empty window. Exciting, isn’t it? You could be a kid
playing with turtle graphics for the first time, it’s so much fun. But what it needs now is
a dash of color:
(.setColor gfx (java.awt.Color. 255 128 0))
(.fillRect gfx 100 150 75 50)
Now there should be an orange rectangle as well. Perhaps the coloring would make
Martha Stewart cry, but you now have tried out all the basic building blocks you’ll
need to complete the original task: you have a function that returns a seq of coordi-
nates and their xor values, you have a window you can draw into, and you know how to
draw rectangles of different colors. Bear in mind that if you move the actual frame
with the mouse, your beautiful graphics will disappear. This is just an artifact of this
limited experiment and can be avoided using the full Java Swing capabilities.
Download from Wow! eBook <www.wowebook.com>

54
CHAPTER 3 Dipping our toes in the pool
3.4.3
Putting it all together
What’s left to do? Use the graphics functions you just saw to draw the xor values you
created earlier:
(doseq [[x y xor] (xors 200 200)]
(.setColor gfx (java.awt.Color. xor xor xor))
(.fillRect gfx x y 1 1))
The xors function you created earlier generates a seq of
vectors, if you remember, where each vector has three
elements: the x and y for your coordinates and the xor
value that goes with them. The first line here uses
destructuring to assign each of those three values to new
locals x, y, and xor, respectively.
The second line sets the “pen” color to a gray level
based on the xor value, and the final line draws a single-
pixel rectangle at the current coordinates. The resulting
Figure 3.1 Visualization of
graphic is shown in figure 3.1.
xor. This is the graphic drawn
But just because you’ve succeeded doesn’t mean you
by the six or so lines of code
have to quit. You’ve built up some knowledge and a bit of
we’ve looked at so far—a
visual representation of
a toolbox, so why not play with it a little?
Clojure’s bit-xor function.
3.4.4
When things go wrong
For example, the pattern appears to cut off in the middle—perhaps you’d like to see a
bit more. Re-enter that last expression, but this time try larger limits:
(doseq [[x y xor] (xors 500 500)]
(.setColor gfx (java.awt.Color. xor xor xor))
(.fillRect gfx x y 1 1))
; java.lang.IllegalArgumentException:
; Color parameter outside of expected range: Red Green Blue
Whoops. Something went wrong, but what exactly? This gives you a perfect opportu-
nity to try out one final REPL tool. When an exception is thrown from something you
try at the REPL, the result is stored in a Var named *e. This allows you to get more
detail about the expression, such as the stack trace:
(.printStackTrace *e)
; java.lang.IllegalArgumentException: Color parameter outside of
; expected range: Red Green Blue
; at clojure.lang.Compiler.eval(Compiler.java:4639)
; at clojure.core$eval__5182.invoke(core.clj:1966)
; at clojure.main$repl__7283$read_eval_print__7295.invoke(main.clj:180)
; ...skipping a bit here...
; Caused by: java.lang.IllegalArgumentException: Color parameter
; outside of expected range: Red Green Blue
; at java.awt.Color.testColorValueRange(Color.java:298)
; at java.awt.Color.<init>(Color.java:382)
; ...skipping a bit more...
; ... 11 more
;=> nil
Download from Wow! eBook <www.wowebook.com>
Using the REPL to experiment
55
That’s a lot of text, but don’t panic. Learning to read Java stack traces will be useful, so
let’s pick it apart.
The first thing to understand is the overall structure of the trace—there are two
“causes.” The original or root cause of the exception is listed last—this is the best
place to look first.4 The name and text of the exception there are the same as the
REPL printed for us in the first place, though they won’t always be. So let’s look at that
next line:
at java.awt.Color.testColorValueRange(Color.java:298)
Like most lines in the stack trace, this has four parts: the name of the class, the name
of the method, the filename, and finally the line number:
at <class>.<method or constructor>(<filename>:<line>)
In this case, the function name is testColorValueRange, which is defined in Java’s
own Color.java file. Unless this means more to you than it does to us, let’s move on to
the next line:
at java.awt.Color.<init>(Color.java:382)
It appears that it was the Color’s constructor (called <init> in stack traces) that called
that test function you saw earlier. So now the picture is pretty clear—when you con-
structed a Color instance, it checked the values you passed in, decided they were
invalid, and threw an appropriate exception.
If this weren’t enough, you could continue walking down the stack trace until the
line
... 11 more
This is your cue to jump up to the cause listed before this one to find out what the
next 11 stack frames were.
To fix your invalid Color argument, you can just adjust the xors function to return
only legal values using the rem function, which returns the remainder so you can keep
the results under 256:
(defn xors [xs ys]
(for [x (range xs) y (range ys)]
[x y (rem (bit-xor x y) 256)]))
Note that you’re redefining an existing function here. This is perfectly acceptable and
well-supported behavior. Before moving on, create a function that takes a graphics
object and clears it:
(defn clear [g] (.clearRect g 0 0 200 200))
Calling (clear gfx) will clear the frame, allowing the doseq form you tried before to
work perfectly.
4
This is a runtime exception, the most common kind. If you misuse a macro or find a bug in one, you may see
compile-time exceptions. The trace will look similar but will have many more references to Compiler.java. For
these traces, the most recent exception (listed first) may be the only one that identifies the filename and line
number in your code that’s at fault.
Download from Wow! eBook <www.wowebook.com>

56
CHAPTER 3 Dipping our toes in the pool
3.4.5
Just for fun
The bit-xor function does produce an interesting image, but perhaps you wonder
what other functions might look like. Try adding another parameter to xors so that
you can pass in whatever function you’d like to look at. Because it’s not just bit-xor
anymore, change the name while you’re at it:
(defn f-values [f xs ys]
(for [x (range xs) y (range ys)]
[x y (rem (f x y) 256)]))
You might as well wrap your call to setSize, clear, and the doseq form in a function
as well:
(defn draw-values [f xs ys]
(clear gfx)
(.setSize frame (java.awt.Dimension. xs ys))
(doseq [[x y v] (f-values f xs ys)]
(.setColor gfx (java.awt.Color. v v v))
(.fillRect gfx x y 1 1)))
This allows you to try out different functions and ranges quite easily. More nice exam-
ples are shown in figure 3.2, resulting from the following:
(draw-values bit-and 256 256)
(draw-values + 256 256)
(draw-values * 256 256)
If this were the beginning or some awkward middle stage of a large project, you’d
have succeeded in pushing past this troubling point and could now take the functions
you’ve built and drop them into the larger project.
By trying everything out at the REPL, you’re encouraged to try smaller pieces
rather than larger ones. The smaller the piece, the shorter the distance down an
incorrect path you’re likely to go. Not only does this reduce the overall development
time, but it provides developers more frequent successes that can help keep morale
and motivation high through even
tough stages of a project. But trial-and-
error exploration isn’t enough. An
intuitive basis in Clojure is also
needed to become highly effective.
Throughout this book, we’ll help you
to build your intuition in Clojure Figure 3.2 Three possible results from draw-
values. The draw-values function you’ve written
through discussions of its idioms and can be used to create a variety of graphics. Here are
its motivating factors and rationale.
examples, from left to right, of bit-and, +, and *.
3.5
Summary
We started slowly in this chapter in order to take a breather from the sprint that was
chapter 2. Truthiness in Clojure observes a simple rule: every object is true all the
time, unless it’s nil or false. Second, in many Lisp-like languages, the empty list ()
Download from Wow! eBook <www.wowebook.com>
Summary
57
and the truth value nil are analogous—this is known as nil-punning—but in Clojure
this isn’t the case. Instead, idiomatic Clojure employs the (seq (rest _)) idiom in
the form of the next function to provide a mechanism fostering “form follows func-
tion” and also to eliminate errors associated with falsety/empty-seq disparity. Finally,
destructuring provides a powerful mechanism, a mini-language for binding if you will,
for partially or entirely pulling apart the constituent components of composite types.
Our trek through the REPL illustrated the power in having the whole language
(Graham 2001) at your disposal. As a Clojure programmer, you’ll spend a lot of time
in the REPL, and pretty soon you won’t know how you lived without it.
In the next chapter, we’ll touch on matters concerning Clojure’s seemingly inno-
cent scalar data types. Although in most cases these scalars will expose powerful pro-
gramming techniques, be forewarned: as you’ll see, the picture isn’t always rosy.
Download from Wow! eBook <www.wowebook.com>
Download from Wow! eBook <www.wowebook.com>
Part 2
Data types
Clojure has squirreled away interesting tidbits even among its data types.
The scalar types include some less common items such as keywords and rational
numbers, and the composite types are all immutable. In this part, we’ll explore
all of them in detail.
Download from Wow! eBook <www.wowebook.com>
Download from Wow! eBook <www.wowebook.com>
On scalars
It requires a very unusual mind to
undertake the analysis of the obvious.
—Alfred North Whitehead
This chapter covers
Understanding precision
Trying to be rational
When to use keywords
Symbolic resolution
Regular expressions—the second problem
So far, we’ve covered a somewhat eclectic mix of theoretical and practical concerns.
This brings us now to a point where we can dive deeper into a fundamental topic:
how Clojure deals with scalar values, including numeric, symbolic, and regular
expression values, and how they behave as data and sometimes as code.
A scalar data type is one that can only hold one value at a time of a number, sym-
bol, keyword, string, or character. Most of the use cases for Clojure’s scalar data
types will be familiar to you. But there are some nuances that should be observed.
Clojure’s scalar data types exist in an interesting conceptual space. Because of its
symbiotic nature, some of the scalar type behaviors walk a conceptual line between
61
Download from Wow! eBook <www.wowebook.com>
62
CHAPTER 4 On scalars
pure Clojure semantics and host semantics. This chapter provides a rundown of some
of the idiomatic uses of Clojure’s scalar data types as well as some pitfalls that you
might encounter. In most cases, Clojure will shield you from the quirks of its host, but
there are times when they’ll demand attention. Clojure’s scalar types have the poten-
tial to act like Sybil—sweet and kind one moment, vicious and vile the next—requir-
ing some thought to handle properly. We’ll also talk about this duality and address its
limitations and possible mitigation techniques. Additionally, we’ll address the age-old
topic of Lisp-1 versus Lisp-2 implementations and how Clojure approaches the matter.
Finally, we’ll talk briefly about Clojure’s regular expression literals and how they’re
typically used.
We’ll first cover matters of numerical precision and how the Java Virtual Machine
works to thwart your attempts at mathematical nirvana.
4.1
Understanding precision
Numbers in Clojure are by default as precise1 as they need to be. Given enough mem-
ory, you could store the value of Pi accurately up to a billion places and beyond; in
practice, values that large are rarely needed. But it’s sometimes important to provide
perfect accuracy at less-precise values. When dealing with raw Clojure functions and
forms, it’s a trivial matter to ensure such accuracy; it’s handled automatically. Because
Clojure encourages interoperability with its host platform, the matter of accuracy
becomes less than certain. This section will talk about real matters of precision related
to Clojure’s support for the Java Virtual Machine. As it pertains to programming lan-
guages,2 numerical precision is proportional to the mechanisms used for storing
numerical representations. The Java language specification describes the internal rep-
resentation of its primitive types thus limiting their precision. Depending on the class
of application specialization, a programmer could go an entire career and never be
affected by Java’s precision limitations. But many industries require perfect accuracy
of arbitrarily precise computations, and it’s here that Clojure can provide a great
boon; but with this power come some pointy edges, as we’ll discuss shortly.
4.1.1
Truncation
Truncation refers to the limiting of accuracy for a floating-point number based on a
deficiency in the corresponding representation. When a number is truncated, its pre-
cision is limited such that the maximum number of digits of accuracy is bound by the
number of bits that can “fit” into the storage space allowed by its representation. For
floating-point values, Clojure truncates by default. Therefore, if high precision is
required for your floating-point operations, then explicit typing is required, as seen
with the use of the M literal in the following:
1
In a future version of Clojure, this arbitrary precision won’t be the default, but will require explicit flagging
(with the aforementioned M for decimal numbers and N for longs). Additionally, overflow of primitive num-
bers will always signal an exception.
2
As opposed to arithmetic precision.
Download from Wow! eBook <www.wowebook.com>
Understanding precision
63
(let [imadeuapi 3.14159265358979323846264338327950288419716939937M]
(println (class imadeuapi))
imadeuapi)
; java.math.BigDecimal
;=> 3.14159265358979323846264338327950288419716939937M
(let [butieatedit 3.14159265358979323846264338327950288419716939937]
(println (class butieatedit))
butieatedit)
; java.lang.Double
;=> 3.141592653589793
As we show, the local butieatedit is truncated because the default Java double type is
insufficient. On the other hand, imadeuapi uses Clojure’s literal notation, a suffix
character M, to declare a value as requiring arbitrary decimal representation. This is
one possible way to mitigate truncation for a immensely large range of values, but as
we’ll explore in section 4.2, it’s not a guarantee of perfect precision.
4.1.2
Promotion
Clojure is able to detect when overflow occurs, and will promote the value to a numer-
ical representation that can accommodate larger values. In many cases, promotion
results in the usage of a pair of classes used to hold exceptionally large values. This pro-
motion within Clojure is automatic, as the primary focus is first correctness of numeri-
cal values, then raw speed. It’s important to remember that this promotion will occur,
as shown in the following listing, and your code should accommodate3 this certainty.
Listing 4.1 Automatic promotion in Clojure
(def clueless 9)
(class clueless)
;=> java.lang.Integer
(class (+ clueless 9000000000000000))
;=> java.lang.Long
(class (+ clueless 90000000000000000000))
;=> java.math.BigInteger
(class (+ clueless 9.0))
;=> java.lang.Double
Java itself has a bevy of contexts under which automatic type conversion will occur, so
we advise you to familiarize yourself with those (Lindholm 1999) when dealing with
Java native libraries.
3 In the example, it’s important to realize that the actual class of the value is changing, so any functions or meth-
ods reliant on specific types might not work as expected.
Download from Wow! eBook <www.wowebook.com>
64
CHAPTER 4 On scalars
4.1.3
Overflow
Integer and long values in Java are subject to overflow errors. When an integer calcu-
lation results in a value that’s larger than 32 bits of representation will allow, the bits of
storage will “wrap” around. When you’re operating in Clojure, overflow won’t be an
issue for most cases, thanks to promotion. But when dealing with numeric operations
on primitive types, overflow can occur. Fortunately in these instances an exception
will occur rather than propagating inaccuracies:
(+ Integer/MAX_VALUE Integer/MAX_VALUE)
;=> java.lang.ArithmeticException: integer overflow
Clojure provides a class of unchecked integer and long mathematical operations that
assume that their arguments are primitive types. These unchecked operations will
overflow if given excessively large values:
(unchecked-add (Integer/MAX_VALUE) (Integer/MAX_VALUE))
;=> -2
You should take care with unchecked operations, because there’s no way to detect
overflowing values and no reliable way to return from them. Use the unchecked func-
tions only when overflow is desired.
4.1.4
Underflow
Underflow is the inverse of overflow, where a number is so small that its value collapses
into zero. Simple examples of underflow for float and doubles can be demonstrated:
(float 0.0000000000000000000000000000000000000000000001)
;=> 0.0
1.0E-430
;=> 0.0
Underflow presents a danger similar to overflow, except that it occurs only with
floating-point numbers.
4.1.5
Rounding errors
When the representation of a floating-point value isn’t sufficient for storing its actual
value, then rounding errors will occur (Goldberg 1994). Rounding errors are an espe-
cially insidious numerical inaccuracy, as they have a habit of propagating throughout a
computation and/or build over time, leading to difficulties in debugging. There’s a
famous case involving the failure of a Patriot missile caused by a rounding error, result-
ing in the death of 28 U.S. soldiers in the first Gulf War (Skeel 1992). This occurred
due to a rounding error in the representation of a count register’s update interval. The
timer register was meant to update once every 0.1 seconds, but because the hardware
couldn’t represent 0.1 directly, an approximation was used instead. Tragically, the
approximation used was subject to rounding error. Therefore, over the course of 100
hours, the rounding accumulated into a timing error of approximately 0.34 seconds.
Download from Wow! eBook <www.wowebook.com>
Trying to be rational
65
Listing 4.2 Illustrating the Patriot missile tragedy
(let [aprox-interval (/ 209715 2097152)
Patriot’s approx 0.1
actual-interval (/ 1 10)
Clojure’s accurate 0.1
hours (* 3600 100 10)
actual-total (double (* hours actual-interval))
aprox-total (double (* hours aprox-interval))]
(- actual-total aprox-total))
;=> 0.34332275390625
In the case of the Patriot missile, the deviation of 0.34 seconds was enough to cause a
catastrophic software error, resulting in its ineffectiveness. When human lives are at
stake, the inaccuracies wrought from rounding errors are unacceptable. For the most
part, Clojure will be able to maintain arithmetic accuracies within a certain range, but
you shouldn’t take for granted that such will be the case when interacting with Java
libraries.
One way to contribute to rounding errors is to introduce doubles and floats into
an operation. In Clojure, any computation involving even a single double will result in
a value that’s a double:
(+ 0.1M 0.1M 0.1M 0.1 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M)
;=> 0.9999999999999999
Can you spot the double?
This discussion was Java-centric, but Clojure’s ultimate goal is to be platform-
agnostic, and the problem of numerical consistency across platforms is a nontrivial
matter. It’s still unknown whether the preceding points will be universal across host
platforms, so please bear in mind that they should be reexamined when using Clojure
outside the context of the JVM. Now that we’ve identified the root issues when dealing
with numbers in Clojure, we’ll dive into a successful mitigation technique for dealing
with them—rationals.
4.2
Trying to be rational
Clojure provides a data type representing a rational number, and all of its core mathe-
matical functions operate with rational numbers. Clojure’s rationals allow for arbi-
trarily large numerators and denominators. We won’t go into depth about the
limitations of floating-point operations, but the problem can be summarized simply.
Given a finite representation of an infinitely large set, a determination must be made
which finite subset is represented. In the case of standard floating-point numbers as
representations of real numbers, the distribution of represented numbers is logarith-
mic (Kuki 1973) and not one-for-one. What does this mean in practice? It means that
requiring more accuracy in your floating-point operations increases the probability
that the corresponding representation won’t be available. In these circumstances,
you’ll have to settle for approximations. But Clojure’s rational number type provides a
way to retain perfect accuracy when needed.
Download from Wow! eBook <www.wowebook.com>
66
CHAPTER 4 On scalars
4.2.1
Why be rational?
Of course, Clojure provides a decimal type that’s boundless relative to your computer
memory, so why wouldn’t you just use those? In short, you can, but decimal operations
can be easily corrupted, especially when working with existing Java libraries (Kahan
1998) taking and returning primitive types. Additionally, in the case of Java, its under-
lying BigDecimal class is finite in that it uses a 32-bit integer to represent the number
of digits to the right of the decimal place. This can represent an extremely large range
of values perfectly, but it’s still subject to error:
1.0E-430000000M
;=> 1.0E-430000000M
1.0E-4300000000M
;=> java.lang.RuntimeException: java.lang.NumberFormatException
Even if you manage to ensure that your BigDecimal values are free from floating-point
corruption, you can never protect them from themselves. At some point or another, a
floating-point calculation will encounter a number such as 2/3 that will always require
rounding, leading to subtle, yet propagating errors. Finally, floating-point arithmetic
is neither associative nor distributive, which may lead to the shocking results shown in
this listing.
Listing 4.3 Floating-point arithmetic isn’t associative or distributive.
(def a 1.0e50)
(def b -1.0e50)
(def c 17.0e00)
(+ (+ a b) c)
;=> 17.0
Associativity should
(+ a (+ b c))
guarantee 17.0 also
;=> 0.0
(let [a (float 0.1)
b (float 0.2)
c (float 0.3)]
(=
(* a (+ b c))
Distributive should
(+ (* a b) (* a c))))
guarantee equality
;=> false
Therefore, for absolutely precise calculations, rationals are the best choice.4
4.2.2
How to be rational
Aside from the rational data type, Clojure provides functions that can help to main-
tain your sanity: ratio?, rational?, and rationalize. Additionally, taking apart ratio-
nals is also a trivial matter.
4 In the case of irrational numbers like Pi, all bets are off.
Download from Wow! eBook <www.wowebook.com>
Trying to be rational
67
The best way to ensure that your calculations remain as accurate as possible is to
ensure that they’re all done using rational numbers. As shown in the following listing,
the shocking results from using floating-point numbers have been eliminated.
Listing 4.4 Being rational preserves associativity and distributive natures.
(def a (rationalize 1.0e50))
(def b (rationalize -1.0e50))
(def c (rationalize 17.0e00))
(+ (+ a b) c)
;=> 17
(+ a (+ b c))
Associativity
;=> 17
preserved
(let [a (rationalize 0.1)
b (rationalize 0.2)
c (rationalize 0.3)]
(=
(* a (+ b c))
Distributive
(+ (* a b) (* a c))))
nature preserved
;=> true
To ensure that your numbers remain rational, you can use rational? to check
whether a given number is one and then use rationalize to convert it to one. There
are a few rules of thumb to remember if you want to maintain perfect accuracy in your
computations:
1
Never use Java math libraries unless they return results of BigDecimal, and even
then be suspicious.
2
Don’t rationalize values that are Java float or double primitives.
3
If you must write your own high-precision calculations, do so with rationals.
4
Only convert to a floating-point representation as a last resort.
Finally, you can extract the constituent parts of a rational using the numerator and
denominator functions:
(numerator (/ 123 10))
;=> 123
(denominator (/ 123 10))
;=> 10
You might never need perfect accuracy in your calculations. When you do, Clojure pro-
vides tools for maintaining sanity, but the responsibility to maintain rigor lies with you.
4.2.3
Caveats of rationality
Like any tool, Clojure’s rational type is a double-edged sword. The calculation of ratio-
nal math, though accurate, isn’t nearly as fast as with floats or doubles. Each operation
in rational math has an overhead cost (such as finding the least common denomina-
tor) that should be accounted for. It does you no good to use rational operations if
speed is a primary concern above accuracy.
Download from Wow! eBook <www.wowebook.com>
68
CHAPTER 4 On scalars
That covers the numerical scalars, so we’ll move on to two data types that you may
not be familiar with unless you happen to come from a background in the Lisp family
of languages: keywords and symbols.
4.3
When to use keywords
The purpose of Clojure keywords, or symbolic identifiers, can sometimes lead to confu-
sion for first-time Clojure programmers, because their analogue isn’t often found5 in
other languages. This section will attempt to alleviate the confusion and provide some
tips for how keywords are typically used.
4.3.1
How are keywords different from symbols?
Keywords always refer to themselves. What this means is that the keyword :magma
always has the value :magma, whereas the symbol ruins may refer to any legal Clojure
value or reference.
AS KEYS
Because keywords are self-evaluating and provide fast equality checks, they’re almost
always used in the context of map keys. An equally important reason to use keywords
as map keys is that they can be used as functions, taking a map as an argument, to per-
form value lookups:
(def population {:zombies 2700, :humans 9})
(:zombies population)
;=> 2700
(println (/ (:zombies population)
(:humans population))
"zombies per capita")
; 300 zombies per capita
This leads to much more concise code.
AS ENUMERATIONS
Often, Clojure code will use keywords as enumeration values, such as :small,
:medium, and :large. This provides a nice visual delineation within the source code.
AS MULTIMETHOD DISPATCH VALUES
Because keywords are used often as enumerations, they’re ideal candidates for dis-
patch values for multimethods, which we’ll explore in more detail in section 9.1.
AS DIRECTIVES
Another common use for keywords is to provide a directive to a function, multi-
method, or macro. A simple way to illustrate this is to imagine a simple function pour,
shown in listing 4.5, that takes two numbers and returns a lazy sequence of the range
of those numbers. But there’s also a mode for this function that takes a keyword :tou-
jours, which will instead return an infinite lazy range starting with the first number
and continuing “forever.”
5 Ruby has a symbol type that acts, looks, and is used similarly to Clojure keywords.
Download from Wow! eBook <www.wowebook.com>
When to use keywords
69
Listing 4.5 Using a keyword as a function directive
(defn pour [lb ub]
(cond
(= ub :toujours) (iterate inc lb)
:else (range lb ub)))
(pour 1 10)
;=> (1 2 3 4 5 6 7 8 9)
(pour 1 :toujours)
; ... runs forever
An illustrative bonus with pour is that the macro cond itself uses a directive :else to
mark the default conditional case. In this case, cond uses the fact that the keyword
:else is truthy; any keyword (or truthy value) would’ve worked just as well.
4.3.2
Qualifying your keywords
Keywords don’t belong to any specific namespace, although they may appear to if
namespace qualification is used:
::not-in-ns
;=> :user/not-in-ns
The prefix portion of the keyword marked as :user/ only looks like it’s denoting an
owning namespace; in fact, it’s a prefix gathered from the current namespace by the
Clojure reader. Observe the use of arbitrary prefixing:
(ns another)
:user/in-another
;=> :user/in-another
:haunted/name
;=> :haunted/name
In the first case, we created a namespace another and created a keyword :user/in-
another that appears to belong to the user namespace, but in fact is prefixed. In the
second example, we created a keyword :haunted/name showing that the prefix doesn’t
have to belong to a namespace at all, given that one named haunted certainly doesn’t
exist. But the fact that keywords aren’t members of any given namespace doesn’t mean
that namespace-qualifying them is pointless. Instead, it’s often more clear to do so,
especially when a namespace aggregates a specific functionality and its keywords are
meaningful in that context.
Separating the plumbing from the domain
Within a namespace named crypto, the keywords ::rsa and ::blowfish make
sense as being namespace-qualified. Likewise, should we create a namespace
aquarium, then using ::blowfish within is contextually meaningful. Likewise, when
adding metadata to structures, you should consider using qualified keywords as keys
and directives if their intention is domain-oriented. Observe the following code:
Download from Wow! eBook <www.wowebook.com>
70
CHAPTER 4 On scalars
(continued)
(defn do-blowfish [directive]
(case directive
:aquarium/blowfish (println "feed the fish")
:crypto/blowfish
(println "encode the message")
:blowfish
(println "not sure what to do")))
(ns crypto)
(user/do-blowfish :blowfish)
; not sure what to do
(user/do-blowfish ::blowfish)
; encode the message
(ns aquarium)
(user/do-blowfish :blowfish)
; not sure what to do
(user/do-blowfish ::blowfish)
; feed the fish
When switching to different namespaces using ns, you can use the namespace-qual-
ified keyword syntax to ensure that the correct domain-specific code path is executed.
Namespace qualification is especially important when you’re creating ad-hoc hierar-
chies and defining multimethods, both discussed in section 9.2.
4.4
Symbolic resolution
In the previous section, we covered the differences between symbols and keywords.
Whereas keywords were fairly straightforward, symbols abide by a slightly more com-
plicated system for lookup resolution.
Symbols in Clojure are roughly analogous to identifiers in many other languages—
words that refer to other things. In a nutshell, symbols are primarily used to provide a
name for a given value. But in Clojure, symbols can also be referred to directly, by
using the symbol or quote function or the ' special operator. Symbols tend to be dis-
crete entities from one lexical contour to another, and often even within a single con-
tour. Unlike keywords, symbols aren’t unique based solely on name alone, as you can
see in the following:
(identical? 'goat 'goat)
;=> false
The reason identical? returns false in this example is because each goat symbol is a
discrete object that only happens to share a name and therefore a symbolic represen-
tation. But that name is the basis for symbol equality:
(= 'goat 'goat)
;=> true
(name 'goat)
"goat"
Download from Wow! eBook <www.wowebook.com>
Symbolic resolution
71
The identical? function in Clojure only ever returns true when the symbols are in
fact the same object:
(let [x 'goat y x] (identical? x y))
;=> true
In the preceding example, x is also a symbol, but when evaluated in the (identical?
x x) form it returns the symbol goat, which is actually being stored on the runtime
call stack. The question arises: why not make two identically named symbols the same
object? The answer lies in metadata, which we discuss next.
4.4.1
Metadata
Clojure allows the attachment of metadata to various objects, but for now we’ll focus
on attaching metadata to symbols. The with-meta function takes an object and a map
and returns another object of the same type with the metadata attached. The reason
why equally named symbols are often not the same instance is because each can have
its own unique metadata:
(let [x (with-meta 'goat {:ornery true})
y (with-meta 'goat {:ornery false})]
[(= x y)
(identical? x y)
(meta x)
(meta y)])
;=> [true false {:ornery true} {:ornery false}]
The two locals x and y both hold an equal symbol 'goat, but they’re different
instances, each containing separate metadata maps obtained with the meta function.
The implications of this are that symbol equality isn’t dependent on metadata or iden-
tity. This equality semantic isn’t limited to symbols, but is pervasive in Clojure, as we’ll
demonstrate throughout this book. You’ll find that keywords can’t hold metadata6
because any equally named keyword is the same object.
4.4.2
Symbols and namespaces
Like keywords, symbols don’t belong to any specific namespace. Take, for example,
the following code:
(ns where-is)
(def a-symbol 'where-am-i)
a-symbol
;=> where-am-i
(resolve 'a-symbol)
;=> #'where-is/a-symbol
à-symbol
;=> where-is/a-symbol
6 Java class instances, including strings, can’t hold metadata either.
Download from Wow! eBook <www.wowebook.com>
72
CHAPTER 4 On scalars
The initial evaluation of a-symbol shows the expected value where-am-i. But attempt-
ing to resolve the symbol using resolve and using syntax-quote returns what looks
like (as printed at the REPL) a namespace-qualified symbol. This is because a symbol’s
qualification is a characteristic of evaluation and not inherent in the symbol at all.
This also applies to symbols qualified with class names. This evaluation behavior will
prove beneficial when we discuss macros in chapter 8, but for now we can summarize
the overarching idea known as Lisp-1 (Gabriel 2001).
4.4.3
Lisp-1
Clojure is what’s known as a Lisp-1, which in simple terms means it uses the same
name resolution for function and value bindings. In a Lisp-2 programming language
like Common Lisp, these name resolutions are performed differently depending on
the context of the symbol, be it in a function call position or a function argument
position. There are many arguments for and against both Lisp-1 and Lisp-2, but
against Lisp-1 one downside bears consideration. Because the same name-resolution
scheme is used for functions and their arguments, there’s a real possibility of
shadowing existing functions with other locals or Vars. Name shadowing isn’t neces-
sarily non-idiomatic if done thoughtfully, but if done accidentally it can lead to some
unexpected and obscure errors. You should take care when naming locals and defin-
ing new functions so that name-shadowing complications can be avoided.
Though name-shadowing errors tend to be rare, the benefit in a simplified mecha-
nism for calling and passing first-class functions far outweighs the negative. Clojure’s
adoption of a Lisp-1 resolution scheme makes for cleaner implementations and there-
fore highlights the solution rather than muddying the waters with the nuances of sym-
bolic lookup. For example, the best function highlights this perfectly in the way that
it takes the greater-than function > and calls it within its body as f:
(defn best [f xs]
(reduce #(if (f % %2) % %2) xs))
(best > [1 3 4 2 7 5 3])
;=> 7
A similar function body using a Lisp-2 language would require the intervention of
another function (in this case funcall) responsible for invoking the function explic-
itly. Likewise, passing any function would require the use of a qualifying tag marking it
as a function object, as seen here:
(defun best (f xs)
(reduce #'(lambda (l r)
(if (funcall f l r) l r))
xs))
(best #'> '(1 3 4 2 7 5 3))
;=> 7
This section isn’t intended to champion the cause of Lisp-1 over Lisp-2, only to high-
light the differences between the two. Many of the design decisions in Clojure provide
succinctness in implementation, and Lisp-1 is no exception. The preference for Lisp-1
Download from Wow! eBook <www.wowebook.com>
Regular expressions—the second problem
73
versus Lisp-2 typically boils down to matters of style and taste; by all practical mea-
sures, they’re equivalent.
Having covered the two symbolic scalar types, we now move into a type that you’re
(for better or worse) likely familiar with: the regular expression.
4.5
Regular expressions—the second problem
Some people, when confronted with a problem, think “I know, I’ll use regular expres-
sions.” Now they have two problems.
—Jamie Zawinski
Regular expressions are a powerful and compact way to find specific patterns in text
strings. Though we sympathize with Zawinski’s attitude and appreciate his wit, some-
times regular expressions are a useful tool to have on hand. Although the full capabil-
ities of regular expressions (or regexes) are well beyond the scope of this section
(Friedl 1997), we’ll look at some of the ways Clojure leverages Java’s regex capabilities.
Java’s regular expression engine is reasonably powerful, supporting Unicode and
features such as reluctant quantifiers and “look-around” clauses. Clojure doesn’t try to
reinvent the wheel and instead provides special syntax for literal Java regex patterns
plus a few functions to help Java’s regex capabilities fit better with the rest of Clojure.
4.5.1
Syntax
A literal regular expression in Clojure looks like this:
#"an example pattern"
This produces7 a compiled regex object that can be used either directly with Java
interop method calls or with any of the Clojure regex functions described later:
(class #"example")
;=> java.util.regex.Pattern
Though the pattern is surrounded with double quotes like string literals, the way
things are escaped within the quotes isn’t the same. This difference is easiest to see in
patterns that use backslash-delimited character classes. When compiled as a regex, a
string "\\d" will match a single digit and is identical to a literal regex without the dou-
ble backslash. Note that Clojure will even print the pattern back out using the literal
syntax:
(java.util.regex.Pattern/compile "\\d")
;=> #"\d"
In short, the only rules you need to know for embedding unusual literal characters or
predefined character classes are listed in the javadoc for Pattern.8
7
Literal regex patterns are compiled to java.util.regex.Pattern instances at read-time. This means, for example,
if you use a literal regex in a loop, it’s not recompiled each time through the loop, but just once when the
surrounding code is compiled.
8
See the online reference at http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html.
Download from Wow! eBook <www.wowebook.com>
74
CHAPTER 4 On scalars
Regular expressions accept option flags, shown in table 4.1, that can make a pat-
tern case-insensitive or enable multiline mode, and Clojure’s regex literals starting
with (?<flag>) set the mode for the rest of the pattern.
Table 4.1 Regex flags: these are the flags that can be used within Clojure regular expression patterns,
their long name, and a description of what they do. See Java's documentation for the java.util.
regex.Pattern class for more details.
Flag
Flag name
Description
d
UNIX_LINES
., ^, and $ match only the Unix line terminator '\n'.
i
CASE_INSENSITIVE
ASCII characters are matched without regard to upper or lower case.
x
COMMENTS
Whitespace and comments in the pattern are ignored.
m
MULTILINE
^ and $ match near line terminators instead of only at the beginning or
end of the entire input string.
s
DOTALL
. matches any character including the line terminator.
u
UNICODE_CASE
Causes the i flag to use Unicode case insensitivity instead of ASCII.
For example, the pattern #"(?i)yo" would match the strings “yo”, “yO”, “Yo”, and “YO”.
4.5.2
Functions
Java’s regex Pattern object has several methods that can be used directly, but only
split is used regularly to split a string into an array9 of Strings, breaking the original
where the pattern matches:
(seq (.split #"," "one,two,three"))
;=> ("one" "two" "three")
The re-seq function is Clojure’s regex workhorse. It returns a lazy seq of all matches
in a string, which means it can be used to efficiently test whether a string matches at
all or to find all matches in a string or a mapped file:
(re-seq #"\w+" "one-two/three")
;=> ("one" "two" "three")
The preceding regular expression has no capturing groups, so each match in the
returned seq is simply a string. A capturing group in the regex causes each returned
item to be a vector:
(re-seq #"\w*(\w)" "one-two/three")
;=> (["one" "e"] ["two" "o"] ["three" "e"])
9 Java arrays don’t print very pleasantly at the Clojure REPL, so we used seq in this example so you can see the
Strings inside.
Download from Wow! eBook <www.wowebook.com>
Summary
75
So where .split returns the text between regex matches, re-seq returns the matches
themselves.10 Now that we’ve looked at some nice functions you can use, we’ll talk
about one object you shouldn’t.
4.5.3
Beware of mutable matchers
Java’s regular expression engine includes a Matcher object that mutates in a non-
thread-safe way as it walks through a string finding matches. This object is exposed by
Clojure via the re-matcher function and can be used as an argument to re-groups
and the single-parameter form of re-find. We highly recommend avoiding all of
these unless you’re certain you know what you’re doing. These dangerous functions
are used internally by the implementations of some of the recommended functions
described earlier, but in each case they’re careful to disallow access to the Matcher
object they use. Use Matchers at your own risk, or better yet don’t use them directly11
at all.
4.6
Summary
Clojure’s scalar types generally work as expected, but its numerical types have a poten-
tial for frustration in certain situations. Though you may rarely encounter issues with
numerical precision, keeping in mind the circumstances under which they occur
might prove useful in the future. Given its inherent arbitrary-precision big decimal
and rational numerics, Clojure provides the tools for perfectly accurate calculations.
Keywords in Clojure serve many purposes and are ubiquitous in idiomatic code. When
dealing directly with symbols, Clojure’s nature as a Lisp-1 defines the nature of how
symbolic resolution occurs. Finally, Clojure provides regular expressions as first-class
data types, and their usage is encouraged where appropriate.
As you might’ve speculated, this chapter was nice and short due to the relative sim-
plicity of scalar types. In the following chapter, we’ll step it up a notch or 10 when cov-
ering Clojure’s composite data types. Though scalars are interesting and deeper than
expected, the next chapter will start you on your way to understanding Clojure’s true
goal: providing a sane approach to application state.
10 If you want both at the same time, you may want to look at the partition function in the clojure-contrib
library, found in the clojure.contrib.string namespace.
11 The clojure.contrib.string namespace has a bevy of functions useful for leveraging regular expres-
sions.
Download from Wow! eBook <www.wowebook.com>
Composite data types
It is better to have 100 functions
operate on one data structure than 10
functions on 10 data structures.
—Alan Perlis
This chapter covers
Persistence, sequences, and complexity
Vectors: creating and using them in all their varieties
Lists: Clojure’s code form data structure
How to use persistent queues
Persistent sets
Thinking in maps
Putting it all together: finding the position of items in a
sequence
Clojure provides a rich set of composite data types and we’ll cover them all: vectors,
lists, queues, sets, and maps. In this chapter, we’ll dig into the strengths and weak-
nesses of each. We’ll spend more time on vectors and maps than on the other types,
because those two are used in a wider variety of circumstances and warrant the
extra discussion. Finally, we’ll discuss the design of a simple function to leverage
76
Download from Wow! eBook <www.wowebook.com>
Persistence, sequences, and complexity
77
many of the lessons learned in this chapter, and you’ll gain specific insight into the
preceding quote. By the way, we use the terms composite types and collections inter-
changeably, so please bear that in mind as we proceed.
Before we look at the primary collection types individually, we’ll discuss the things
they have in common. For example, you may have heard of Clojure’s sequence
abstraction —all the persistent collections use it, so we’ll examine that as well as some
algorithmic complexity concepts we’ll be referring to throughout the chapter.
5.1
Persistence, sequences, and complexity
Clojure’s composite data types have some unique properties compared to composites
in many mainstream languages. Terms such as persistent and sequence come up, and not
always in a way that makes their meaning clear. In this section we’ll define their mean-
ings carefully. We’ll also briefly examine the topic of algorithmic complexity and Big-O
notation as they apply to Clojure collections.
The term persistent is particularly problematic because it means something differ-
ent in other contexts. In the case of Clojure, we believe that a phrase immortalized by
Inigo Montoya from the novel and subsequent film The Princess Bride summarizes your