}
Of course, this describes implementation details and shouldn’t be considered fact in
future version of Clojure. In fact, as shown before, you were able to add implementa-
tions for the parts of the DynaFrame class at the REPL because Clojure generates a stub
that looks up concrete implementations through Vars. But these details are useful for
describing the logical product of :gen-class and compile. The :gen-class directive
with the argument :name joy.gui.DynaFrame creates a class vaguely resembling the
following Java source:
package joy.gui;
public class DynaFrame extends javax.swing.JFrame {
public final Object state;
Download from Wow! eBook <www.wowebook.com>
Clojure gen-class and GUI programming
215
public DynaFrame(String title) {
Object r = clojure.lang.RT.var("joy.gui.DynaFrame", "df-init")
.invoke(title);
Object cargs = clojure.lang.RT.nth(r, 0);
state = clojure.lang.RT.nth(r, 1);
super((String) clojure.lang.RT.nth(cargs, 0));
}
public static String version() { return "1.0"; }
// Delegate to the display function var
public void display(Object the_this, java.awt.Container c) {
return clojure.lang.RT.var("joy.gui.DynaFrame", "df-display")
.invoke(the_this, c);
}
. . .
}
The :gen-class directive creates a class that’s a delegate for the Vars (prefixed as spec-
ified with df-) located in the corresponding namespace, contains the state, and also
holds any static methods. This is a lot of detail to contend with, but understanding it’s
important when arranging your Clojure projects to take advantage of code compilation.
One final important point when using gen-class is the semantics surrounding the
:impl-ns directive. Our example relies on the fact that the gen-class namespace is
the same as the implementation namespace (the :impl-ns ), meaning that the compi-
lation will transitively compile all of the implementation functions. On the other
hand, when your implementation and gen-class namespaces are distinct, you no lon-
ger suffer transitive compilation. This provides the benefit of allowing a mixture of
compiled (class files) and uncompiled (.clj files) Clojure products.
10.2.2 Exploring user interface design and development with Clojure
Before we begin, we’ll devise a simple model (_why 20073) for exploring user inter-
face design. We don’t have to complicate matters, because the goal is only to get a gen-
eral idea of how Clojure makes a typically painful task like Java GUI development a joy.
To achieve this modest goal, we’ll need some simple containers illustrated in figure
10.4: shelves, stacks, and splitters.
Because DynaFrame requires a java.awt.
shelf
stack
splitter
Container as its displayed element, we’ll make
each container a derivative thereof. This allows
the containers to nest, helping to build richer
GUIs. Finally, their forms should mirror their
graphical layout, within reason. These three
containers are implemented in the following
Figure 10.4 Basic GUI containers: using
only a handful of rudimentary containers,
listing.
we can build neato GUI prototypes.
3 Our GUI model in this section is based loosely on the Ruby framework Shoes created by _why. Thank you sir,
wherever you are.
Download from Wow! eBook <www.wowebook.com>
216
CHAPTER 10 Java.next
Listing 10.4 Simple GUI containers
(ns joy.gui.socks
(:import
(joy.gui DynaFrame)
(javax.swing Box BoxLayout JTextField JPanel
JSplitPane JLabel JButton
JOptionPane)
(java.awt BorderLayout Component GridLayout FlowLayout)
(java.awt.event ActionListener)))
(defn shelf [& components]
(let [shelf (JPanel.)]
(.setLayout shelf (FlowLayout.))
(doseq [c components] (.add shelf c))
shelf))
(defn stack [& components]
(let [stack (Box. BoxLayout/PAGE_AXIS)]
(doseq [c components]
(.setAlignmentX c Component/CENTER_ALIGNMENT)
(.add stack c))
stack))
(defn splitter [top bottom]
(doto (JSplitPane.)
(.setOrientation JSplitPane/VERTICAL_SPLIT)
(.setLeftComponent top)
(.setRightComponent bottom)))
These simple GUI elements are built on top of the Java Swing library, where each sub-
widget in the components argument is added to the properly configured Container-
derived parent. These are good as a starting point, but still there’s nothing to display
unless we dive into the Swing API directly. We can do one better than that by providing
a simple base set of widgets: buttons, labels, and text boxes.
Listing 10.5 A set of simple widgets
(defn button [text f]
(doto (JButton. text)
(.addActionListener
(proxy [ActionListener] []
(actionPerformed [_] (f))))))
(defn txt [cols t]
(doto (JTextField.)
(.setColumns cols)
(.setText t)))
(defn label [txt] (JLabel. txt))
The button element takes a function executed on a mouse-click, so we’ll now provide
a JavaScript-like alert function as a simple action:
(defn alert
([msg] (alert nil msg))
([frame msg]
(javax.swing.JOptionPane/showMessageDialog frame msg)))
Download from Wow! eBook <www.wowebook.com>


Clojure gen-class and GUI programming
217
Figure 10.5 DynaFrame alerts: we
Figure 10.6 A much more elaborate DynaFrame GUI:
can create slightly more complex
there’s no limit to the complexity of this simple GUI
GUIs and attach actions on the fly.
model. Go ahead and experiment to your heart’s content.
Having built all of these GUI elements, we’ll describe the first simple GUI as shown in
figure 10.5.
It seems simple, if not pointless. But you might be pleasantly surprised with the con-
cise code used to describe it:
(.display gui
(splitter
(button "Procrastinate" #(alert "Eat Cheetos"))genclass
(button "Move It" #(alert "Couch to 5k"))))
These widgets are adequate enough to create richer user interfaces, and to illustrate
we’ll add one more widget builder for grid-like elements:
(defn grid [x y f]
(let [g (doto (JPanel.)
(.setLayout (GridLayout. x y)))]
(dotimes [i x]
(dotimes [j y]
(.add g (f))))
g))
With a small amount of code, we can build the richer user interface in figure 10.6.
Listing 10.6 A more complex GUI example
(.display gui
(let [g1 (txt 10 "Charlemagne")
g2 (txt 10 "Pippin")
r (txt 3 "10")
d (txt 3 "5")]
(splitter
(stack
(shelf (label "Player 1") g1)
(shelf (label "Player 2") g2)
(shelf (label "Rounds ") r
(label "Delay ") d))
Download from Wow! eBook <www.wowebook.com>
218
CHAPTER 10 Java.next
(stack
(grid 21 11 #(label "-"))
(button "Go!" #(alert (str (.getText g1) " vs. "
(.getText g2) " for "
(.getText r) " rounds, every "
(.getText d) " seconds.")))))))
Though not perfect, it gives you a good idea how to extend these functions to provide
a finer level of control over layout and positioning, as well as ways to provide more
functionality to create richer interfaces. How would you go about creating an agile
environment for incremental GUI development using plain Java? Clojure allows you to
start with a powerful set of primitives and incrementally refine them until they suit
your exact needs.
Though this section started as a description of creating a simple dynamic frame
using the gen-class facility, we felt it was worthwhile to expand into the realm of
dynamic, incremental development. There are times when AOT compilation is abso-
lutely necessary (such as client requirements), but our advice is to avoid it if at all pos-
sible. Instead, leverage the dynamic nature of Clojure to its fullest, designing your
system to fit into that model.
10.3 Clojure’s relationship to Java arrays
In general, the need to delve into arrays should be limited, but such casual dismissal
isn’t always apropos. In this section, we’ll cover some of the uses for Java arrays in Clo-
jure, including but not limited to arrays as multimethod dispatch, primitive versus ref-
erence arrays, calling variadic functions and constructors, and multi-dimensional
arrays.
10.3.1 Types of arrays: primitive and reference
As mentioned in section 4.1, Clojure numbers are of the boxed variety, but in many
cases the Clojure compiler can resolve the correct call for primitive interoperability
calls. But it can never resolve the need to pass a primitive array when a reference array
is provided instead.
CREATING PRIMITIVE ARRAYS
The Java class java.lang.StringBuilder provides4 a method .append(char[]) that
appends the primitive chars in the passed array to its end. But our first instinct for
making this happen in Clojure won’t bear fruit:
(doto (StringBuilder. "abc")
(.append (into-array [\x \y \z])))
;=> #<StringBuilder abc[Ljava.lang.Character;@65efb4be>
The problem lies in that Clojure’s into-array function doesn’t return a primitive
array of char[], but instead a reference array of Character[], forcing the Clojure
4 When dealing with and manipulating strings, your best options can almost always be found in the core
clojure.string namespace or the clojure.contrib.string namespace in the Clojure contrib library.
Download from Wow! eBook <www.wowebook.com>
Clojure’s relationship to Java arrays
219
compiler to resolve the call as to the StringBuilder.append(Object) method
instead. That the Array class is a subclass of Object is a constant cause for headache in
Java and clearly can be a problem5 for Clojure as well. What we really want to do is
ensure that a primitive array is used as the argument to .append, which we do here:
(doto (StringBuilder. "abc")
(.append (char-array [\x \y \z])))
;=> #<StringBuilder abcxyz>
Clojure provides a number of primitive array-building functions that work similarly to
char-array, as summarized in the following list.
boolean-array
double-array
long-array
byte-array
float-array
object-array
char-array
int-array
short-array
You could also use the make-array and into-array functions to create primitive
arrays:
(let [ary (make-array Integer/TYPE 3 3)]
(dotimes [i 3]
(dotimes [j 3]
(aset ary i j (+ i j))))
(map seq ary))
;=> ((0 1 2) (1 2 3) (2 3 4))
(into-array Integer/TYPE [1 2 3])
;=> #<int[] [I@391be9d4>
Populating arrays can often be an iterative affair, as seen in the previous snippet, but
there are often more concise ways to do so when creating reference arrays.
CREATING REFERENCE ARRAYS
To intentionally create an array of a particular reference type, or of compatible types,
use the into-array function, passing in a sequence of objects:
(into-array ["a" "b" "c"])
;=> #<String[] [Ljava.lang.String;@3c3ac93e>
(into-array [(java.util.Date.) (java.sql.Time. 0)])
;=> #<Date[] [Ljava.util.Date;@178aab40>
(into-array ["a" "b" 1M])
; java.lang.IllegalArgumentException: array element type mismatch
(into-array Number [1 2.0 3M 4/5])
;=> #<Number[] [Ljava.lang.Number;@140b6e46>
The function into-array determines the type of the resulting array based on the first
element of the sequence, and each subsequent element type must be compatible (a
5
In this example, it’s preferred that a “java.lang.IllegalArgumentException: No matching method found”
exception be thrown, because StringBuilder doesn’t have a method matching .append(Character[]) or
even .append(Object[]).
Download from Wow! eBook <www.wowebook.com>
220
CHAPTER 10 Java.next
subclass). To create a heterogeneous array of java.lang.Object, use the to-array or
to-array-2d function:
(to-array-2d [[1 2 3]
[4 5 6]])
;=> #<Object[][] [[Ljava.lang.Object;@bdccedd>
(to-array ["a" 1M #(%) (proxy [Object] [])])
;=> #<Object[] [Ljava.lang.Object;@18987a33>
(to-array [1 (int 2)])
;=> #<Object[] [Ljava.lang.Object;@6ad3c65d>
Be wary: primitives will be autoboxed when using either to-array or to-array-2d.
10.3.2 Array mutability
Because JVM arrays are mutable, you need to be aware that their contents can change
at any point. For example:
(def ary (into-array [1 2 3]))
(def sary (seq ary))
sary
;=> (1 2 3)
What happens to sary if we change the contents of ary?
(aset ary 0 42)
sary
;=> (42 2 3)
The seq view of an array is that of the live array and therefore subject to concurrent
modification. Be cautious when sharing arrays from one function to the next, and
especially across threads. Note that this can be especially disastrous should an array
change in the middle of a sequential operation, such as the use of the higher-order
array functions amap and areduce, as might be used to define a sum-of-squares func-
tion6 for arrays:
(defn asum-sq [xs]
(let [dbl (amap xs i ret
(* (aget xs i)
(aget xs i)))]
(areduce dbl i ret 0
(+ ret (aget dbl i)))))
(asum-sq (float-array [1 2 3 4 5]))
;=> 55.0
At any point during the processing of asum-sq, the underlying array could change,
causing inaccurate results or worse. You should take great care when using Java’s
mutable arrays, though sharing only the seq of an array is perfectly safe because
there’s no way to get at the array when you only have a reference to the seq.
6 This function is fairly clear but slower than it should be. We’ll make it faster in sections 12.1 and 12.5.
Download from Wow! eBook <www.wowebook.com>
Clojure’s relationship to Java arrays
221
10.3.3 That unfortunate naming convention
You might’ve noticed (how could you miss?) the ugly names printed by the Clojure
REPL whenever an array is evaluated. There’s logic to this madness, as part of the jum-
ble is the legal name of the class corresponding to the array—the part formed as
[Ljava.lang.String;. For example, the previous name corresponded to a 1D array
of strings. The representation for a 2D array of strings is then [[Ljava.lang.String;,
and it therefore follows that [[[Ljava.lang.String; is a 3D array of strings. Are you
sensing a pattern here? Table 10.1 lays it out.
Using what you know about arrays, the class representation names can be used to
do things such as multimethod dispatch:
(what-is (into-array ["a" "b"]))
;=> "1d String"
(what-is (to-array-2d [[1 2][3 4]]))
;=> "2d Object"
(what-is (make-array Integer/TYPE 2 2 2 2))
;=> "Primitive 4d int"
You can create methods for identifying arrays and returning a descriptive string using
the <indexterm><primary>java.lang.Class/forName</primary></indexterm>Class/
forName method as shown:
(defmulti what-is class)
(defmethod what-is (Class/forName "[Ljava.lang.String;") [a] "1d String")
(defmethod what-is (Class/forName "[[Ljava.lang.Object;") [a] "2d Object")
(defmethod what-is (Class/forName "[[[[I") [a] "Primitive 4d int")
Though not the most beautiful task to perform in Clojure, it’s easy to understand
once you’ve grasped how the array class names are constructed.
Representation
Array type
[Ljava.lang.Object;
Reference array
[B
Primitive byte array
[I
Primitive int array
[C
Primitive char array
[S
Primitive short array
[F
Primitive float array
[D
Primitive double array
[J
Primitive long array
[Z
Primitive boolean array
Representation
Dimension
[
1D
[[
2D
Table 10.1 Array type class
...
and so on...
names and dimensions
Download from Wow! eBook <www.wowebook.com>
222
CHAPTER 10 Java.next
10.3.4 Multidimensional arrays
Observe what happens when the following call is tried:
(what-is (into-array [[1.0] [2.0]]))
; java.lang.IllegalArgumentException: No method in multimethod
; 'what-is' for dispatch value: class [Lclojure.lang.PersistentVector;
The problem is that the into-array function builds a 1D array of persistent vectors,
but we wanted a 2D array of doubles. In order to do this, the array would have to be
built differently:
(defmethod what-is (Class/forName "[[D") [a] "Primitive 2d double")
(defmethod what-is (Class/forName "[Lclojure.lang.PersistentVector;") [a]
"1d Persistent Vector")
(what-is (into-array (map double-array [[1.0] [2.0]])))
;=> "Primitive 2d double"
(what-is (into-array [[1.0] [2.0]]))
;=> "1d Persistent Vector"
We had to use the map function with double-array on the inner arrays in order to
build the properly typed outer array. When working with multidimensional arrays, be
sure that you know what your inner elements should be on creation and create them
accordingly.
10.3.5 Variadic method/constructor calls
There’s no such thing as a variadic constructor or method at the bytecode level,
although Java provides syntactic sugar at the language level. Instead, variadic methods
expect an array as their final argument, and this is how they should be accessed in Clo-
jure interop scenarios. Take, for example, the call to the String/format function:
(String/format "An int %d and a String %s" (to-array [99, "luftballons"]))
;=> "An int 99 and a String luftballons"
That covers most of the high points regarding arrays in Clojure interoperability. We’ll
touch on them briefly when we talk about performance considerations in chapter 12,
but for now we’ll move on to a more interesting topic: the interoperability underpin-
nings relating to Clojure’s implementation.
10.4
All Clojure functions implement...
Clojure functions are highly amenable to interoperability. Their underlying classes
implement a number of useful interfaces that you can investigate by running
(ancestors (class #())). Most of the resulting classes are only applicable to the
internals of Clojure itself, but a few interfaces are useful in interop scenarios:
java.util.concurrent.Callable, java.util.Comparator, and java.lang.Runnable.
In this section, we’ll talk briefly about each and also provide simple examples.
Download from Wow! eBook <www.wowebook.com>
All Clojure functions implement...
223
10.4.1 java.util.Comparator
Simply put, the java.util.Comparator interface defines the signature for a single
method .compare that takes two objects l and r and returns -1 if l < r, 0 if l == r, and
> 0 if l > r. The static Java method Collections/sort provides an implementation
that takes a derivative of java.util.List and a Comparator and destructively sorts the
list provided. Using this knowledge, we can provide some basic infrastructure for the
remainder of this subsection:
(import '[java.util Comparator Collections ArrayList])
(defn gimme [] (ArrayList. [1 3 4 8 2]))
(doto (gimme)
(Collections/sort (Collections/reverseOrder)))
;=> #<ArrayList [8, 4, 3, 2, 1]>
In order to write a simple comparator that provides a reverse-sort Comparator, we
might naively do so:
(doto (gimme)
(Collections/sort
(reify Comparator
(compare [this l r]
(cond
(> l r) -1
(= l r) 0
:else 1)))))
;=> #<ArrayList [8, 4, 3, 2, 1]>
Though this works, Clojure provides a better way by allowing the use of a function as
the Comparator directly. You can couple this knowledge with the fact that Clojure
already provides numerous functions useful for comparison, as shown next.
Listing 10.7 Useful comparison functions
(doto (gimme) (Collections/sort #(compare %2 %1)))
compare function
;=> #<ArrayList [8, 4, 3, 2, 1]>
(doto (gimme) (Collections/sort >))
Less-than function
;=> #<ArrayList [8, 4, 3, 2, 1]>
(doto (gimme) (Collections/sort <))
Greater-than function
;=> #<ArrayList [1, 2, 3, 4, 8]>
(doto (gimme) (Collections/sort (complement <)))
complement function
;=> #<ArrayList [8, 4, 3, 2, 1]>
When presented with numerous possible implementation strategies, often the best
one in Clojure is the simplest.
10.4.2 java.lang.Runnable
Java threads expect an object implementing the java.lang.Runnable interface meant
for computations returning no value. We won’t get into the specifics of threaded
Download from Wow! eBook <www.wowebook.com>
224
CHAPTER 10 Java.next
computation until the next chapter, but the next two examples are simple enough to
require little a priori knowledge on the matter. If you wish to pass a function to
another Java thread, it’s as simple as providing it as an argument to the Thread
constructor:
(doto (Thread. #(do (Thread/sleep 5000)
(println "haikeeba!")))
.start)
; => #<Thread Thread[Thread-3,5,main]>
; ... 5 seconds later
; haikeeba!
This scenario is unlikely to occur often, because Clojure’s core concurrency features
are often sufficient for most needs. But that’s not always the case, and therefore it’s nice
to know that raw Clojure functions can be used seamlessly in the JVM’s concurrency API.
10.4.3 java.util.concurrent.Callable
The Java interface java.util.concurrent.Callable is specifically meant to be used
in a threaded context for computations returning a value. You can use a Clojure func-
tion using Java’s java.util.concurrentFutureTask class representing a “computa-
tion to occur later”:
(import '[java.util.concurrent FutureTask])
(let [f (FutureTask. #(do (Thread/sleep 5000) 42))]
(.start (Thread. #(.run f)))
(.get f))
; ... 5 seconds later
;=> 42
The call to FutureTask.get as the last expression will stop execution (a behavior
known as blocking) until the function passed to the constructor completes. Because the
function in question sleeps for 5 seconds, the call to .get must wait.
Clojure’s interoperability mechanisms are a two-way street. Not only do they allow
Java APIs to work seamlessly within Clojure, but they also provide ways for Clojure
functions to work in Java APIs. In the next section, we’ll continue on this theme of
bidirectional interop with a discussion on the ways that Clojure’s collection types can
also be used in traditional Java APIs.
10.5
Using Clojure data structures in Java APIs
Clojure functions are ready to use in many Java APIs, and as it turns out, so are its col-
lection types. Just as the Clojure collections are separated along three distinct equality
partitions7 (maps, sequences, and sets), so too are its levels of Java collection interop-
erability support. The Java Collections Framework has a nice high-level design philos-
ophy centered around working against interfaces. These interfaces are additionally
cognizant of immutability, in that the mutable parts are optional and the immutable
7 A refresher on equality partitions can be found in section 5.1.2 and throughout the remainder of chapter 5.
Download from Wow! eBook <www.wowebook.com>
Using Clojure data structures in Java APIs
225
parts are clearly demarcated. In this section, we’ll give a brief rundown of possible
ways that Clojure collections can be used within traditional Java APIs adhering to the
immutable collection protocols.
10.5.1 java.util.List
Clojure sequential collections conform to the immutable parts of the java.util.List
interface, which in turn extends the java.util.Collection and java.lang.Iterable
interfaces. You can see this conformance in action in the following listing.
Listing 10.8 java.util.List conformance for sequences and seqs
(.get '[a b c] 1)
Vectors
;=> b
(.get (repeat :a) 138)
Lazy seqs
;=> :a
(.containsAll '[a b c] '[b c])
Vectors also collections
;=> true
(.add '[a b c] 'd)
Sequences not mutable
; java.lang.UnsupportedOperationException
That Clojure sequences and seqs don’t provide the mutable API of typical Java collec-
tions is obvious. But the implications are that you can’t use them in all Java APIs, such
as you might attempt when requiring that a vector be sorted destructively with a Java
API call:
(java.util.Collections/sort [3 4 2 1])
; java.lang.UnsupportedOperationException
A better approach is to either use the method used in the previous section using a Clo-
jure function, or even better to use the Clojure’s sort function instead.
10.5.2 java.lang.Comparable
The interface java.lang.Comparable is the cousin of the Comparator interface.
Comparator refers to objects that can compare two other objects, whereas Comparable
refers to an object that can compare itself to another object:
(.compareTo [:a] [:a])
;=> 0
(.compareTo [:a :b] [:a])
;=> 1
(.compareTo [:a :b] [:a :b :c])
;=> -1
(sort [[:a :b :c] [:a] [:a :b]])
;=> ([:a] [:a :b] [:a :b :c])
One thing to note is that Clojure’s vector implementation is currently the only collec-
tion type that implements the java.lang.Comparable interface providing the
Download from Wow! eBook <www.wowebook.com>
226
CHAPTER 10 Java.next
.compareTo method. As a result, attempting to compare a different collection type to
a vector leads to a confusing error message:
(.compareTo [1 2 3] '(1 2 3))
; java.lang.ClassCastException: clojure.lang.PersistentList
; cannot be cast to clojure.lang.IPersistentVector
Pay no attention to that class-cast exception behind the curtain.
10.5.3 java.util.RandomAccess
In general, the java.util.RandomAccess interface is used to indicate that the data
type provides constant time indexed access to its elements. This allows for algorithms
to follow optimized paths accordingly. This optimization is generally performed by
using the .get method for access rather than an iterator:
(.get '[a b c] 2)
;=> c
Vectors are currently the only Clojure collection type that can make such guarantees.
10.5.4 java.util.Collection
The java.util.Collection interface lies at the heart of the Java Collections Frame-
work, and classes implementing it can play in many of Java’s core collections APIs. A
useful idiom taking advantage of this fact is the use of a Clojure sequence as a model
to build a mutable sequence for use in the Java Collections API, as shown:
(defn shuffle [coll]
(seq (doto (java.util.ArrayList. coll)
java.util.Collections/shuffle)))
(shuffle (range 10))
;=> (3 9 2 5 4 7 8 6 1 0)
It’s difficult to write a proper sequence-shuffling function, so the shuffle function
takes full advantage of an existing Java API that has been tested and used extensively
for years. As an added bonus, shuffle is mostly8 functional, idiomatic, and fast. Clo-
jure favors immutability but doesn’t trap you into it when there are practical solutions
to be leveraged.
JAVA.UTIL.MAP
Like most of the Clojure collections, its maps are analogous to Java maps in that they
can be used in nonmutating contexts. But immutable maps have the added advantage
of never requiring defensive copies and will act exactly the same as unmodifiable Java
maps:
(java.util.Collections/unmodifiableMap
(doto (java.util.HashMap.) (.put :a 1)))
;=> #<UnmodifiableMap {:a=1}>
8 shuffle isn’t referentially transparent. Can you see why?
Download from Wow! eBook <www.wowebook.com>
definterface
227
(into {} (doto (java.util.HashMap.) (.put :a 1)))
;=> {:a 1}
In both cases, any attempt to modify the map entry classes of the maps will throw an
exception.
10.5.5 java.util.Set
In the case of Java and Clojure sets, the use of mutable objects9 as elements is highly
frowned upon:
(def x (java.awt.Point. 0 0))
(def y (java.awt.Point. 0 42))
(def points #{x y})
points
;=> #{#<Point java.awt.Point[x=0,y=0]> #<Point java.awt.Point[x=0,y=42]>}
Everything looks peachy at this point, but introducing mutability into the equation
has devastating costs:
(.setLocation y 0 0)
points
;=> #{#<Point java.awt.Point[x=0,y=0]> #<Point java.awt.Point[x=0,y=0]>}
Oh boy. Not only have we confused the set points by modifying its entries out from
underneath it, but we’ve also circumvented Clojure’s value-based semantics and the
nature of set-ness. Dealing with mutable objects is extremely difficult to reason about,
especially when dealing with collections of them. The gates of a mutable class are wide
open, and at any point during the execution of your programs this fact can be
exploited, willingly or not. But you can’t always avoid dealing with mutable nasties in
Clojure code because of a strict adherence to fostering interoperability.
We’ve covered the two-way interop for functions and now collection types, but we
have one final path to traverse: the use and benefits of Clojure’s definterface macro.
10.6
definterface
As we mentioned in section 9.3, Clojure was built on abstractions in the host platform
Java. Types and protocols help to provide a foundation for defining your own abstrac-
tions in Clojure itself, for use within a Clojure context. But when interoperating with
Java code, protocols and types won’t always suffice. Therefore, you need to be able to
generate interfaces in some interop scenarios, and also for performance in cases
involving primitive argument and return types. In this section, we’ll talk briefly about
generating Java interfaces as the syntax, use cases, and purposes are likely familiar.
10.6.1 Generating interfaces on the fly
When you AOT-compile a protocol, you generate a public interface by the same name,
with the methods defined. The code in listing 10.9 uses definterface to define an
9 Clojure’s mutable reference types used to represent a logical identity are perfectly safe to use in sets. We’ll
explore the reference types in exquisite detail in the next chapter.
Download from Wow! eBook <www.wowebook.com>
228
CHAPTER 10 Java.next
interface ISliceable. This interface is used to define an abstract thing that has the
ability to be sliced using a method slice, which takes start and end indices of type int.
Likewise, the interface defines a method sliceCount that returns an int representing
the number of possible slices.
Listing 10.9 An interface defining a sliceable object
(definterface ISliceable
(slice [^int s ^int e])
(^int sliceCount []))
;=> user.ISliceable
You’ll notice the inclusion of the type decoration ^int on the arguments to slice and
the return type of sliceCount. For now you can assume that they operate the same as
a type declaration in most languages providing them. They look similar to type hints
discussed in section 12.1, except that only in definterface are primitive hints sup-
ported. Now we can create an instance implementing the user.ISliceable interface,
as shown next.
Listing 10.10 A dummy reified ISliceable
(def dumb
(reify user.ISliceable
(slice [_ s e] [:empty])
(sliceCount [_] 42)))
(.slice dumb 1 2)
;=> [:empty]
(.sliceCount dumb)
;=> 42
There’s nothing terribly surprising about dumb, but you can instead implement it via
deftype, proxy, gen-class, or even a Java class. Note that definterface works even
without AOT compilation.
We can now take definterface to the next logical step and extend the ISliceable
interface to other types using a well-placed protocol.
Listing 10.11 Using a protocol to extend ISliceable
(defprotocol Sliceable
(slice [this s e])
(sliceCount [this]))
(extend user.ISliceable
Sliceable
{:slice (fn [this s e] (.slice this s e))
:sliceCount (fn [this] (.sliceCount this))})
(sliceCount dumb)
;=> 42
(slice dumb 0 0)
;=> [:empty]
Download from Wow! eBook <www.wowebook.com>
Be wary of exceptions
229
By extending the ISliceable interface along Sliceable, ISliceable is able to partic-
ipate in the protocol, meaning that you have the possibility for extending other types,
even final types such as String, as shown next.
Listing 10.12 Extending strings along the Sliceable protocol
(defn calc-slice-count [thing]
"Calculates the number of possible slices using the formula:
(n + r - 1)!
------------
r!(n - 1)!
where n is (count thing) and r is 2"
(let [! #(reduce * (take % (iterate inc 1)))
n (count thing)]
(/ (! (- (+ n 2) 1))
(* (! 2) (! (- n 1))))))
(extend-type String
Sliceable
(slice [this s e] (.substring this s (inc e)))
(sliceCount [this] (calc-slice-count this)))
(slice "abc" 0 1)
;=> "ab"
(sliceCount "abc")
;=> 6
The advantages of using definterface over defprotocol are restricted entirely to the
fact that the former allows primitive types for arguments and returns. At some point in
the future, the same advantages will likely be extended to the interfaces generated, so
use definterface sparingly and prefer protocols unless absolutely necessary.
10.7
Be wary of exceptions
There’s been much debate on the virtues of checked exceptions in Java, so we won’t
cover that here. Instead, we’ll stick to the facts regarding the nuances the JVM imposes
on Clojure’s error-handling facilities. Before we begin, consider the following view on
the use of exceptions in Clojure source:
When writing Clojure code, use errors to mean can’t continue and exceptions to mean
can or might continue .
We’ll attempt to constrain ourselves to the generalities of exception handling in this
section. If you desire information on deciphering exception messages, we talked about
that in section 3.4. If you’re curious about the effects of exceptions on continuation-
passing style, then refer back to section 7.3.4. We discussed the behavior of Clojure to
attempt to supplant numerical inaccuracies by throwing exceptions in section 4.1.3. If
you instead want to learn about the interplay between exceptions and Clojure’s refer-
ence types, then such matters can be found throughout chapter 11. Finally, if you have
no idea what an exception is, then we discuss the basics in section 1.5.8.
Download from Wow! eBook <www.wowebook.com>
230
CHAPTER 10 Java.next
10.7.1 A bit of background regarding exceptions
The behavior of Clojure’s exception features directly spawns from the JVM enforcing
the promulgation of checked exceptions. Virtuous or not in the context of Java devel-
opment, checked exceptions are antithetical to closures and higher-order functions.
Checked exceptions require that not only should the thrower and the party responsi-
ble for handling them declare interest, but every intermediary is also forced to partic-
ipate. These intermediaries don’t have to actively throw or handle exceptions
occurring within, but they must declare that they’ll be “passing through.” Therefore,
by including the call to a Java method throwing a checked exception within a closure,
Clojure has two possible alternatives:
Provide a cumbersome exception declaration mechanism on every single func-
tion, including closures.
By default, declare that all functions throw the root Exception or Runtime-
Exception.
And as you can probably guess, Clojure takes the second approach, which leads to a
condition of multilevel wrapping of exceptions as they pass back up the call stack. This
is why you see, in almost any (.printStackTrace *e) invocation, the point of origin of
an error offset by some number of layers of java.lang.RuntimeException. Because
Java interfaces and classes get to decide what types of problems potential derivative
classes and even callers can have, Clojure needs to handle the base
java.lang.Exception at every level, because it has to preserve dynamism in the face
of a closed system. Unless you’re directly calling something that throws typed excep-
tions, your best bet is to catch Exception and then see what you have in context.
10.7.2 Runtime versus compile-time exceptions
There are two contexts in Clojure where exceptions can be thrown: runtime and com-
pile time. In this section we’ll touch on both, explaining how and when to use them.
RUNTIME EXCEPTIONS
The case of runtime exceptions might be the most familiar, because it’s likely to have
been encountered and utilized in your own code. There are two types of runtime
exceptions: errors and exceptions. We can illustrate the difference between the two by
showing you the following:
(defn explode [] (explode))
(try (explode) (catch Exception e "Stack is blown"))
; java.lang.StackOverflowError
So why were we unable to catch the java.lang.StackOverflowError? The reason lies
in Java’s exception class hierarchy and the fact that StackOverflowError isn’t a deriv-
ative of the Exception class, but instead of the Error class:
(try (explode) (catch StackOverflowError e "Stack is blown"))
;=> "Stack is blown"
Download from Wow! eBook <www.wowebook.com>
Be wary of exceptions
231
(try (explode) (catch Error e "Stack is blown"))
;=> "Stack is blown"
(try (explode) (catch Throwable e "Stack is blown"))
;=> "Stack is blown"
(try (throw (RuntimeException.))
(catch Throwable e "Catching Throwable is Bad"))
;=> "Catching Throwable is Bad"
We started with a catch of the most specific exception type StackOverflowError and
gradually decreased specificity until catching Throwable, which as you’ll notice also
catches a RuntimeException. In Java, catching exceptions at the level of Throwable is
considered bad form, and it should generally be viewed the same in Clojure. There-
fore, we suggest that you follow the advice stated in the opening to this section and
reserve those deriving from Errors for conditions that can’t be continued from and
those from Exception indicating possible continuation.
COMPILE-TIME EXCEPTIONS
There are a few ways that you might come across compile-time exceptions, the most
obvious occurring within the body of a macro:
(defmacro do-something [x] `(~x))
(do-something 1)
; java.lang.ClassCastException:
; java.lang.Integer cannot be cast to clojure.lang.IFn
Though the type of the exception is a java.lang.ClassCastException, it was indeed
thrown by the compiler, which you’d see if you were to trace the stack using some-
thing like (for [e (.getStackTrace *e)] (.getClassName e)).10 It’s perfectly accept-
able (and even encouraged) to throw exceptions within your own macros, but it’s
important to make a distinction between a compile-time and runtime exception.
COMPILE-TIME EXCEPTIONS Why delay until runtime the reporting of an error
that at compile time you know exists?
The way to throw a compile-time exception is to make sure your throw doesn’t occur
within a syntax-quoted form, as we show in the following listing.
Listing 10.13 Throwing a compile-time exception
(defmacro pairs [& args]
(if (even? (count args))
`(partition 2 '~args)
(throw (Exception. (str "pairs requires an even number of args")))))
(pairs 1 2 3)
; java.lang.Exception: pairs requires an even number of args
(pairs 1 2 3 4)
;=> ((1 2) (3 4))
10 This is a limited analogy to Groovy’s .? operator. Clojure also provides convenience functions for displaying
and handling stack traces in the clojure.stacktrace namespace.
Download from Wow! eBook <www.wowebook.com>
232
CHAPTER 10 Java.next
Nothing is preventing the exception from being thrown at runtime, but because we
know that pairs requires an even number of arguments, we instead prefer to fail as
early as possible—at compilation time. This difference is clearly demonstrated by
repeating the preceding test in a function definition:
(fn [] (pairs 1 2 3))
; java.lang.Exception: pairs requires an even number of args
A runtime exception wouldn’t have been thrown until this function was called, but
because the pairs macro threw an exception at compile time, users are notified of
their error immediately. Though powerful, you should always try to balance the bene-
fits of compile-time error checking with macros and the advantages that implement-
ing as a function provides (the use in higher-order functions, apply, and so on).
10.7.3 Handling exceptions
There are two ways to handle exceptions and errors, each defined by the way in which
the error-handling mechanisms “flow” through the source. Imagine that you want a
macro that provides a limited11 null-safe (Koenig 2007) arrow that catches any occur-
rence of a NullPointerException in a pipeline:
(defmacro -?> [& forms]
exceptions
`(try (-> ~@forms)
(catch NullPointerException _# nil)))
(try
(+
(-?> 25 Math/sqrt (+ 100))
(Math/sqrt 25)
;=> 105.0
100)
(catch NPE e nil))
(-?> 25 Math/sqrt (and nil) (+ 100))
;=> nil
binding
The flow of any occurrence of NullPointer-
Exception happens from the inner functions of the
(binding [handle prn]
stitched forms. Conceptually, this flow can be viewed
(try
(+
as in figure 10.7, which describes the way that errors
(Math/sqrt 25)
can be caught depending on the direction in which
100)
(catch NPE e
data is moving along the stack.
(handle e))))
The typical (try ... (catch ...)) form would
therefore be used for the case where the handler
Figure 10.7 Outside-in and inside-
out error handling. There are two
catches errors bubbling outward from inner func-
ways to handle errors in Clojure. The
tions and forms, as seen in the -?> macro. But if you
typical way is to let exceptions flow
want to catch errors at their point of origin, you’ll
from the inner forms to the outer.
need a way to pass handlers up the stack. Fortunately,
The other way, discussed in section
13.4, uses dynamic bindings to
Clojure provides a way to do this via its dynamic Var
“reach into” the inner forms to
feature, which will be discussed in section 13.5.
handle them immediately.
11 There are much more comprehensive -?> and .?. macros found in the clojure.contrib.core
namespace, and those are recommended above the one in this section.
Download from Wow! eBook <www.wowebook.com>
Summary
233
10.7.4 Custom exceptions
If you’re inclined to write your own exception and error types, then you’ll need to do
so using the gen-class feature described in section 10.2. JVM exceptions again are a
closed system, and it might be better to explore other possibilities (Houser EK) for
reporting and handling errors in your Clojure code. But, should you wish to ignore
this advice, then bear in mind that it’s rare for Clojure core functions to throw excep-
tions, and even more rarely are they checked exceptions. The idiom is for Clojure to
throw derivatives of RuntimeException or Error, and thus your code should also strive
for this when appropriate.
10.8
Summary
Clojure provides an extensive set of data abstractions via its types and protocols. It
also provides an extensive interoperability facility through proxy, gen-class,
definterface, exception handling, and the implementation of core Java collection
interfaces. Though we stress that types and protocols will give you the performant
abstractions needed for solving most problems, we realize that not all interop scenar-
ios are solved this way. In these circumstances, you should use the features listed in
this chapter to push you the remainder of the way toward your solution. Clojure
embraces Java interoperability, but it does so in specific ways, and with a specific set
of tools.
In the next chapter, we move on to a rather complex topic, and one that Clojure
helps to simplify—shared state concurrency and mutation.
Download from Wow! eBook <www.wowebook.com>
Mutation
This chapter covers
Software transactional memory with multiversion
concurrency control and snapshot isolation
When to use Refs
When to use Agents
When to use Atoms
When to use locks
When to use futures
When to use promises
Parallelism
Vars and dynamic binding
Clojure’s main tenet isn’t the facilitation of concurrency. Instead, Clojure at its core
is concerned with the sane management of state, and facilitating concurrent pro-
gramming naturally falls out of that. The JVM operates on a shared-state concur-
rency model built around juggling fine-grained locks that protect access to shared
data. Even if you can keep all of your locks in order, rarely does such a strategy scale
well, and even less frequently does it foster reusability. But Clojure’s state manage-
ment is simpler to reason about and promotes reusability.
234
Download from Wow! eBook <www.wowebook.com>
Software transactional memory
235
CLOJURE APHORISM A tangled web of mutation means that any change to
your code potentially occurs in the large.
In this chapter, we’ll take the grand tour of
the mutation primitives and see how Clojure
Concurrency
makes concurrent programming not only
vs. parallelism
possible, but fun. Our journey will take us
Concurrency refers to the execu-
through Clojure’s four major mutable refer-
tion of disparate tasks at roughly
ences: Refs, Agents, Atoms, and Vars. When
the same time, each sharing a
common resource. The results of
possible and appropriate, we’ll also point out
concurrent tasks often affect the
the Java facilities for concurrent program-
behavior of other concurrent
ming (including locking) and provide infor-
tasks, and therefore contain an
mation on the trade-offs involved in
element of nondeterminism. Paral-
choosing them. We’ll also explore parallel-
lelism refers to partitioning a task
ism support in Clojure using futures, prom-
into multiple parts, each run at the
same time. Typically, parallel
ises, and a trio of functions pmap, pvalues,
tasks work toward an aggregate
and pcalls.
goal and the result of one doesn’t
Before we dive into the details of Clo-
affect the behavior of any other
jure’s reference types, let’s start with a high-
parallel task, thus maintaining
level overview of Clojure’s software transac-
determinacy.
tional memory ( STM ).
11.1 Software transactional memory with multiversion
concurrency control and snapshot isolation
Software transactional memory
A faster program that doesn’t work right is useless.
—Simon Peyton-Jones
in “Beautiful Concurrency”
In chapter 1, we defined three important terms:
Time —The relative moments when events occur
State —A snapshot of an entity’s properties at a moment in time
Identity —The logical entity identified by a common stream of states occurring
over time
These terms form the foundation for Clojure’s model of state management and muta-
tion. In Clojure’s model, a program must accommodate the fact that when dealing
with identities, it’s receiving a snapshot of its properties at a moment in time, not nec-
essarily the most recent. Therefore, all decisions must be made in a continuum. This
model is a natural one, as humans and animals alike make all decisions based on their
current knowledge of an ever-shifting world. Clojure provides the tools for dealing
with identity semantics via its Ref reference type, the change semantics of which are
governed by Clojure’s software transactional memory; this ensures state consistency
throughout the application timeline, delineated by a transaction.
Download from Wow! eBook <www.wowebook.com>
236
CHAPTER 11 Mutation
11.1.1 Transactions
Within the first few moments of using Clojure’s STM, you’ll notice something different
than you may be accustomed to: no locks. Consequently, because there’s no need for
ad-hoc locking schemes when using STM, there’s no chance of deadlock. Likewise, Clo-
jure’s STM doesn’t require the use of monitors and as a result is free from lost wakeup
conditions. Behind the scenes, Clojure’s STM uses multiversion concurrency control
( MVCC ) to ensure snapshot isolation. In simpler terms, snapshot isolation means that
each transaction gets its own view of the data that it’s interested in. This snapshot is
made up of in-transaction reference values, forming the foundation of MVCC (Ullman
1988). As illustrated in figure 11.1, each transaction merrily chugs along making
changes to in-transaction values only, oblivious to and ambivalent about other transac-
tions. At the conclusion of the transaction, the local values are examined against the
modification target for conflicts. An example of a simple possible conflict is if another
transaction B committed a change to a target reference during the time that transac-
tion A was working, thus causing A to retry. If no conflicts are found, then the in-trans-
action values are committed and the target references are modified with their updated
values. Another advantage that STM provides is that in the case of an exception during
a transaction, its in-transaction values are thrown away and the exception propagated
outward. In the case of lock-based schemes, exceptions can complicate matters ever
more, because in most cases locks need to be released (and in some cases, in the cor-
rect order) before an exception can be safely propagated up the call stack.
Because each transaction has its own isolated snapshot, there’s no danger in retry-
ing—the data is never modified until a successful commit occurs. STM transactions
can easily nest without taking additional measures to facilitate composition. In lan-
guages providing explicit locking for concurrency, matters of composability are often
difficult, if not impossible. The reasons for this are far-reaching and the mitigating
forces (Goetz 2006) complex, but the primary reasons tend to be that lock-based
concurrency schemes often hinge on a secret incantation not explicitly understand-
able through the source itself: for example, the order in which to take and release a
set of locks.
11.1.2 Embedded transactions
In systems providing embedded transactions, it’s often common for transactions to be
nested, thus limiting the scope of restarts (Gray 1992). Embedding transactions within
Clojure operates differently, as summarized in figure 11.2.
In some database systems, transactions can be used to limit the scope of a restart as
shown when transaction embedded.b restarts only as far back as its own scope. Clojure
has but one transaction per thread, thus causing all subtransactions to be subsumed
into the larger transaction. Therefore, when a restart occurs in the (conceptual) sub-
transaction clojure.b, it causes a restart of the larger transaction. Though not shown,
some transaction systems provide committal in each subtransaction; in Clojure, com-
mit only occurs at the outermost larger transaction.
Download from Wow! eBook <www.wowebook.com>














Software transactional memory
237
Figure 11.1 Illustrating an STM retry: Clojure’s STM works much like a database.
embedded
clojure
A
A
B
B
b
b
Figure 11.2 Clojure’s embedded transactions: a restart in
restart
restart
any of Clojure’s embedded transactions A, B, b, and C causes
C
C
a restart in the whole subsuming transaction. This is unlike a
fully embedded transaction system where the subtransactions
commit!
commit!
can be used to restrain the scope of restarts.
11.1.3 The things that STM makes easy
The phrase TANSTAAFL, meaning “There ain’t no such thing as a free lunch,” was
popularized in the excellent sci-fi novel The Moon Is a Harsh Mistress (Heinlein 1966)
and is an apt response to the view that STM is a panacea for concurrency complexities.
Download from Wow! eBook <www.wowebook.com>
238
CHAPTER 11 Mutation
As you proceed through this chapter, we urge you to keep this in the back of your
mind, because it’s important to realize that though Clojure facilitates concurrent pro-
gramming, it doesn’t solve it for you. But there are a few things that Clojure’s STM
implementation simplifies in solving difficult concurrent problems.
CONSISTENT INFORMATION
The STM allows you to perform arbitrary sets of read/write operations on arbitrary
sets of data in a consistent (Papadimitriou 1986) way. By providing these assurances,
the STM allows your programs to make decisions given overlapping subsets of informa-
tion. Likewise, Clojure’s STM helps to solve the reporting problem—the problem of
getting a consistent view of the world in the face of massive concurrent modification
and reading, without stopping (locking).
NO NEED FOR LOCKS
In any sized application, the inclusion of locks for managing concurrent access to
shared data adds complexity. There are many factors adding to this complexity, but
chief among them are the following:
You can’t use locks without supplying extensive error handling. This is critical
in avoiding orphaned locks (locks held by a thread that has died).
Every application requires that you reinvent a whole new locking scheme.
Locking schemes often require that you impose a total ordering that’s difficult
to enforce in client code, frequently leading to a priority inversion scenario.
Locking schemes are difficult to design correctly and become increasingly so as the
number of locks grows. Clojure’s STM eliminates the need for locking and as a result
eliminates dreaded deadlock scenarios. Clojure’s STM provides a story for managing
state consistently. Adhering to this story will go a long way toward helping you solve
software problems effectively. This is true even when concurrent programming isn’t a
factor in your design.
ACI
In the verbiage of database transactions is a well-known acronym ACID, which refers to
the properties ensuring transactional reliability. Clojure’s STM provides the first three
properties: atomicity, consistency, and isolation. The other, durability, is missing due to the fact that Clojure’s STM resides in-memory and is therefore subject to data loss in the
face of catastrophic system failure. Clojure relegates the problem of maintaining dura-
bility to the application developer instead of supplying common strategies by default:
database persistence, external application logs, serialization, and so on.
11.1.4 Potential downsides
There are two potential problems inherent in STMs in general, which we’ll only touch
on briefly here.
WRITE SKEW
For the most part, you can write correct programs simply by putting all access and
changes to references in appropriately scoped transactions. The one exception to this
Download from Wow! eBook <www.wowebook.com>
Software transactional memory
239
is write skew, which occurs in MVCC systems such as Clojure’s. Write skew can occur
when one transaction uses the value of a reference to regulate its behavior but doesn’t
write to that reference. At the same time, another transaction updates the value for
that same reference. One way to avoid this would be to do a “dummy write” in the first
transaction, but Clojure provides a less costly solution: the ensure function. This sce-
nario is rare in Clojure applications, but possible.
LIVE-LOCK
Live-lock refers to a set of transaction(s) that repeatedly restart one another. Clojure
combats live-lock in a couple of ways. First, there are transaction restart limits that will
raise an error when breached. Generally this occurs when the units of work within
some number of transactions is too large. The second way that Clojure combats live-
lock is called barging. Barging refers to some careful logic in the STM implementation
allowing an older transaction to continue running while younger transactions retry.
11.1.5 The things that make STM unhappy
Certain things can rarely (if ever) be safely performed within a transaction, and in this
section we’ll talk briefly about each.
I/O
Any I/O operation in the body of a transaction is highly discouraged. Due to restarts,
the embedded I/O could at best be rendered useless, and cause great harm at worst.
It’s advised that you employ the io! macro whenever performing I/O operations:
(io! (.println System/out "Haikeeba!"))
; Haikeeba!
When this same statement is used in a transaction, an exception is thrown:
(dosync (io! (.println System/out "Haikeeba!")))
; java.lang.IllegalStateException: I/O in transaction
Though it may not be feasible to use io! in every circumstance, it’s a good idea to do
so whenever possible.
CLASS INSTANCE MUTATION
Unrestrained instance mutation is often not idempotent, meaning that running a set of
mutating operations multiple times often displays different results.
LARGE TRANSACTIONS
Though the size of transactions is highly subjective, the general rule of thumb when
partitioning units of work should always be get in and get out as quickly as possible.
Though it’s important to understand that transactions will help to simplify the
management of state, you should strive to minimize their footprint in your code. The
use of I/O and instance mutation is often an essential part of many applications; it’s
important to work to separate your programs into logical partitions, keeping I/O and
its ilk on one side, and transaction processing and mutation on the other. Fortunately
for us, Clojure provides a powerful toolset for making the management of mutability
Download from Wow! eBook <www.wowebook.com>
240
CHAPTER 11 Mutation
sane, but none of the tools provide a shortcut to thinking. Multithreaded program-
ming is a difficult problem, independent of specifics, and Clojure’s state-management
tools won’t solve this problem magically. We’ll help to guide you through the proper
use of these tools starting with Clojure’s Ref type.
11.2
When to use Refs
Clojure currently provides four different reference types to aide in concurrent pro-
gramming: Refs, Agents, Atoms, and Vars. All but Vars are considered shared refer-
ences and allow for changes to be seen across threads of execution. The most
important point to remember about choosing between reference types is that
although their features sometimes overlap, each has an ideal use. All the reference
types and their primary characteristics are shown in figure 11.3.
Ref Agent Atom Var
Figure 11.3 Clojure’s four reference types are listed across the
Coordinated
top, with their features listed down the left. Atoms are for lone
Asynchronous
synchronous objects. Agents are for asynchronous actions. Vars
Retriable
are for thread-local storage. Refs are for synchronously
Thread-local
coordinating multiple objects.
The unique feature of Refs is that they’re coordinated. This means that reads and writes
to multiple refs can be made in a way that guarantees no race conditions. Asynchronous
means that the request to update is queued to happen in another thread some time
later, while the thread that made the request continues immediately. Retriable indicates
that the work done to update a reference’s value is speculative and may have to be
repeated. Finally, thread-local means that thread safety is achieved by isolating changes
to state to a single thread.
Value access via the @ reader feature or the deref function provide a uniform client
interface, regardless of the reference type used. On the other hand, the write mecha-
nism associated with each reference type is unique by name and specific behavior, but
dothreads
To illustrate some major points, we’ll use a function dothreads! that launches a
given number of threads each running a function a number of times:
(import '(java.util.concurrent Executors))
(def *pool* (Executors/newFixedThreadPool
(+ 2 (.availableProcessors (Runtime/getRuntime)))))
(defn dothreads! [f & {thread-count :threads
exec-count :times
:or {thread-count 1 exec-count 1}}]
(dotimes [t thread-count]
(.submit *pool* #(dotimes [_ exec-count] (f)))))
The dothreads! function is of limited utility—throwing a bunch of threads at a func-
tion to see if it breaks.
Download from Wow! eBook <www.wowebook.com>
When to use Refs
241
similar in structure. Each referenced value is changed through the application1 of a
pure function. The result of this function will become the new referenced value.
Finally, all reference types allow the association of a validator function via set-
validator that will be used as the final gatekeeper on any value change.
11.2.1 Coordinated, synchronous change using alter
A Ref is a reference type allowing synchronous, coordinated change to its contained
value. What does this mean? By enforcing that any change to a Ref’s value occurs in a
transaction, Clojure can guarantee that change happens in a way that maintains a con-
sistent view of the referenced value in all threads. But there’s a question as to what
constitutes coordination. We’ll construct a simple vector of Refs to represent a 3 x 3
chess board:
(def initial-board
[[:- :k :-]
[:- :- :-]
[:- :K :-]])
(defn board-map [f bd]
(vec (map #(vec (for [s %] (f s))) bd)))
Just as in section 2.4, the lowercase keyword represents a dark king piece and the
uppercase a light king piece. We’ve chosen to represent the board as a 2D vector of
Refs (which are created by the board-map function). There are other ways to repre-
sent our board, but we’ve chosen this because it’s nicely illustrative—the act of moving
a piece would require a coordinated change in two reference squares, or else a change
to one square in one thread could lead to another thread observing that square as
occupied. Likewise, this problem requires synchronous change, because it would be
no good for pieces of the same color to move consecutively. Refs are the only game in
town to ensure that the necessary coordinated change occurs synchronously. Before
you see Refs in action, we need to define auxiliary functions:
(defn reset!
"Resets the board state. Generally these types of functions are a
bad idea, but matters of page count force our hand."
[]
(def board (board-map ref initial-board))
(def to-move (ref [[:K [2 1]] [:k [0 1]]]))
(def num-moves (ref 0)))
(def king-moves (partial neighbors
[[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]] 3))
(defn good-move? [to enemy-sq]
(when (not= to enemy-sq) to))
(defn choose-move [[[mover mpos][_ enemy-pos]]]
[mover (some #(good-move? % enemy-pos)
(shuffle (king-moves mpos)))])
1 Except for ref-set on Refs, reset! on Atoms, and set! on Vars.
Download from Wow! eBook <www.wowebook.com>
242
CHAPTER 11 Mutation
The to-move structure describes the order of moves, so in the base case, it states that
the light king :K at y=2,x=1 moves before the dark king :k at y=0,x=1. We reuse the
neighbors function from section 7.4 to build a legal-move generator for chess king
pieces. We do this by using partial supplied with the kingly position deltas and the
board size. The good-move? function states that a move to a square is legal only if the
enemy isn’t already located there. The function choose-move destructures the to-
move vector and chooses a good move from a shuffled sequence of legal moves. The
choose-move function can be tested in isolation:
(reset!)
(take 5 (repeatedly #(choose-move @to-move)))
;=> ([:K [1 0]] [:K [1 1]] [:K [1 1]] [:K [1 0]] [:K [2 0]])
And now we’ll create a function to make a random move for the piece at the front of
to-move, shown next.
Listing 11.1 Using alter to update a Ref
(defn place [from to] to)
(defn move-piece [[piece dest] [[_ src] _]]
(alter (get-in board dest) place piece)
Place moving piece
(alter (get-in board src ) place :-)
Empty from square
(alter num-moves inc))
(defn update-to-move [move]
(alter to-move #(vector (second %) move)))
Swap
(defn make-move []
(dosync
(let [move (choose-move @to-move)]
(move-piece move @to-move)
(update-to-move move))))
The alter function appears four times within the dosync, so that the from and to posi-
tions, as well as the to-move Refs, are updated in a coordinated fashion. We’re using
the place function as the alter function, which states “given a to piece and a from
piece, always return the to piece.” Observe what occurs when make-move is run once:
(make-move)
;=> [[:k [0 1]] [:K [2 0]]]
(board-map deref board)
;=> [[:- :k :-] [:- :- :-] [:K :- :-]]
@num-moves
;=> 1
We’ve successfully made a change to two board squares, the to-move structure, and
num-moves using the uniform state change model. By itself, this model of state change
is compelling. The semantics are simple to understand: give a reference a function
that determines how the value changes. This is the model of sane state change that
Clojure preaches. But we can now throw a bunch of threads at this solution and still
maintain consistency:
Download from Wow! eBook <www.wowebook.com>

When to use Refs
243
(alter num-moves inc)
-- in-transaction --
(apply inc @num-moves)
9
(apply inc 9)
. . .
Figure 11.4 Alter path: the in-transaction value 9 for
the Ref num-moves is retrieved in the body of the
-- commit time --
transaction and manipulated with the alter function
(commit num-moves)
10
inc. This resulting value 10 is eventually used for the
commit-time value, unless a retry is required.
(defn go [move-fn threads times]
(dothreads! move-fn :threads threads :times times))
(go make-move 100 100)
(board-map #(dosync (deref %)) board)
;=> [[:k :- :-] [:- :- :-] [:K :- :-]]
@to-move
;=> [[:k [0 0]] [:K [2 0]]]
@num-moves
;=> 10001
Figure 11.4 shows that at the time of the transaction, the in-transaction value of the to
square is set to (apply place @SQUARE-REF PIECE). At the end of the transaction, the
STM uses this in-transaction value as the commit value. If any other transaction had
updated any other coordinated Ref before commit time, then the whole transaction
would be retried.
Clojure’s retry mechanism guarantees that the Refs in a transaction are always
coordinated upon commit because all other transactions line up waiting their turn to
commit their coordinated values. Look at what happens should the Ref updates hap-
pen in separate transactions:
(defn bad-make-move []
(let [move (choose-move @to-move)]
(dosync (move-piece move @to-move))
(dosync (update-to-move move))))
(go bad-make-move 100 100)
(board-map #(dosync (deref %)) board)
;=> [[:- :K :-] [:- :- :-] [:- :K :-]]
Clearly something has gone awry, and as we mentioned, the reason lies in splitting the
updates of the to and from Refs into different transactions. Being separated into two
transactions means that they’re (potentially) running on different timelines. Because
board and to-move are dependent, their states must be coordinated, but we’ve broken
that necessity with bad-make-move. Therefore, somewhere along the line board was
updated from two subsequent timelines where it was :K’s turn to move!
As shown in figure 11.5, either transaction can commit or be restarted; but because
the two Refs are no longer in the same transaction, the occurrences of these condi-
tions become staggered over time, leading to inconsistent values.
Download from Wow! eBook <www.wowebook.com>


244
CHAPTER 11 Mutation
Transaction for A
Transaction for B
-- in-transaction --
-- in-transaction --
(apply f @A)
a
(apply f @B)
b
(apply f a)
(apply f b)
. . .
. . .
-- commit time --
-- commit time --
(commit A)
a'
RESTART
Figure 11.5 Splitting coordinated Refs: if Refs A and B should be coordinated,
then splitting their updates across different transactions is dangerous. Value a?
is eventually committed to A, but the update for B never commits due to retry and
coordination is lost. Another error occurs if B’s change depends on A’s value and
A and B are split across transactions. There are no guarantees that the dependent
values refer to the same timeline.
11.2.2 Commutative change with commute
Figure 11.4 showed that using alter can cause a transaction to retry if a Ref it
depends on is modified and committed while it’s running. But there may be circum-
stances where the value of a Ref within a given transaction isn’t important to its com-
pletion semantics. For example, the num-moves Ref is a simple counter, and surely its
value at any given time is irrelevant for determining how it should be incremented. To
handle these loose dependency circumstances, Clojure offers an operation named
commute. What if we were to change the make-move function to use the commute func-
tion instead of alter?
(defn move-piece [[piece dest] [[_ src] _]]
(commute (get-in board dest) place piece)
(commute (get-in board src ) place :-)
(commute num-moves inc))
(reset!)
(go make-move 100 100)
(board-map deref board)
;=> [[:K :- :-] [:- :- :-] [:- :- :k]]
@to-move
;=> [[:K [0 0]] [:k [2 2]]]
Everything looks great! But you can’t assume that the same will work for update-to-
move:
(defn update-to-move [move]
(commute to-move #(vector (second %) move)))
(go make-move 100 100)
(board-map #(dosync (deref %)) board)
;=> [[:- :- :-] [:- :K :-] [:- :- :K]]
@to-move
[[:K [2 2]] [:K [1 1]]]
Download from Wow! eBook <www.wowebook.com>

When to use Refs
245
(commute num-moves inc)
-- in-transaction --
(apply inc @num-moves)
9
(apply inc 9)
. . .
-- commit time --
Figure 11.6 Commute path: the in-transaction value 9 in the
(apply inc @num-moves)
13 num-moves Ref is retrieved in the body of the transaction and
manipulated with the commute function. But the commute
(apply inc 13)
function inc is again run at commit time with the current value
(commit num-moves)
14 13 contained in the Ref. The result of this action serves as the
committed value 14.
Thanks to our rash decision, we’ve once again introduced inconsistency into the system.
But why? The reason lies in the fact that the new update-to-move isn’t amenable to the
semantics of the commute function. commute allows for more concurrency in the STM by
devaluing in-transaction value disparity resulting from another transaction’s commit. In
other words, figure 11.6 shows that the in-transaction value of a Ref is initially set as
when using alter, but the commit time value is reset just before commute commits.
By retrieving the most current value for a Ref at the time of commit, the values
committed might not be those corresponding to the in-transaction state. This leads to
a condition of update reordering that your application must accommodate. Of course,
this new function isn’t commutative because vector doesn’t give the same answer if its
argument order is switched.
Using commute is useful as long as the following conditions aren’t problematic:
The value you see in-transaction may not be the value that gets committed at
commit time.
The function you give to commute will be run at least twice—once to compute
the in-transaction value, and again to compute the commit value. It might be
run any number of times.
11.2.3 Vulgar change with ref-set
The function ref-set is different from alter and commute in that instead of changing
a Ref based on a function of its value, it does so given a raw value:
(dosync (ref-set to-move '[[:K [2 1]] [:k [0 1]]]))
;=> [[:K [2 1]] [:k [0 1]]]
In general, this sort of vulgar change should be avoided. But because the Refs have
become out of sync, perhaps you could be forgiven in using ref-set to fix it—just this
once.
11.2.4 Fixing write-skew with ensure
Snapshot isolation means that within a transaction, all enclosed Ref states represent the
same moment in time. Any Ref value that you see inside a transaction will never change
unless you change it within that transaction. Your algorithms should be devised so that
all you care about is that the values of the references haven’t changed before commit
Download from Wow! eBook <www.wowebook.com>
246
CHAPTER 11 Mutation
(unless your change function is commutative, as mentioned previously). If those val-
ues have changed, then the transaction retries, and you try again. Earlier, we talked
about write skew, a condition occurring when you make decisions based on the in-
transaction value of a Ref that’s never written to, which is also changed at the same
time. Avoiding write skew is accomplished using Clojure’s ensure function, which
guarantees a read-only Ref isn’t modified by another thread. The make-move function
isn’t subject to write skew because it has no invariants on read data and in fact never
reads a Ref that it doesn’t eventually write. This design is ideal because it allows other
threads to calculate moves without having to stop them, while any given transaction
does the same. But in your own applications, you may be confronted with a true read
invariant scenario, and it’s in such a scenario that ensure will help.
11.2.5 Refs under stress
After you’ve created your Refs and written your transactions, and simple isolated tests
are passing, you may yet run into difficulties in larger integration tests because of how
Refs behave under stress from multiple transactions. As a rule of thumb, it’s best to
avoid having both short- and long-running transactions interacting with the same Ref.
Clojure’s STM implementation will usually compensate eventually regardless, but
you’ll soon see some less-than-ideal consequences of ignoring this rule.
To demonstrate this problem, listing 11.2 shows a function designed specifically to
over-stress a Ref. It does this by starting a long-running or slow transaction in another
thread, where work is simulated by a 200ms sleep, but all it’s really doing is reading
the Ref in a transaction. This requires the STM to know of a stable value for the Ref for
the full 200ms. Meanwhile, the main thread runs quick transactions 500 times in a
row, each one incrementing the value in the Ref and thereby frustrating the slow
transaction’s attempts to see a stable value. The STM works to overcome this frustra-
tion by growing the history of values kept for the Ref. But by default this history is lim-
ited to 10 entries, and our perverse function can easily saturate that:
(stress-ref (ref 0))
;=> :done
; r is: 500, history: 10, after: 26 tries
You may see a slightly different number of tries, but the important detail is that the
slow transaction is unable to successfully commit and print the value of r until the
main thread has finished its frantic looping and returned :done. The Ref’s history
started at a default of 0 and grew to 10, but this was still insufficient.
Listing 11.2 How to make a Ref squirm
(defn stress-ref [r]
(let [slow-tries (atom 0)]
(future
Long-running
(dosync
transaction
(swap! slow-tries inc)
(Thread/sleep 200)
@r)
Download from Wow! eBook <www.wowebook.com>
When to use Agents
247
(println (format "r is: %s, history: %d, after: %d tries"
@r (ref-history-count r) @slow-tries)))
(dotimes [i 500]
500 very quick
(Thread/sleep 10)
transactions
(dosync (alter r inc)))
:done))
Remember that our real problem here is mixing short- and long-running transactions
on the same Ref. But if this is truly unavoidable, Clojure allows us to create a Ref with
a more generous cap on the history size:
(stress-ref (ref 0 :max-history 30))
; r is: 410, history: 20, after: 21 tries
;=> :done
Again, your numbers may be different, but this time the Ref’s history grew sufficiently
(reaching 20 in this run) to allow the slow transaction to finish first and report about
r before all 500 quick transactions completed. In this run, only 410 had finished when
the slow transaction committed.
But the slow transaction still had to be retried 20 times, with the history growing
one step large each time, before it was able to complete. If our slow transaction were
doing real work instead of just sleeping, this could represent a lot of wasted comput-
ing effort. If your tests or production environment reveal this type of situation and the
underlying transaction size difference can’t be resolved, one final Ref option can
help. Because you can see that the history will likely need to be 20 anyway, you may as
well start it off closer to its goal:
(stress-ref (ref 0 :min-history 15 :max-history 30))
; r is: 97, history: 19, after: 5 tries
;=> :done
This time the slow transaction finished before even 100 of the quick transactions had
finished; and even though the history grew to roughly the same size, starting it off at
15 meant the slow transaction only retried 4 times before succeeding.
The use of Refs to guarantee coordinated change is generally simple for managing
state in a synchronous fashion, and tuning with :min-history and :max-history is
rarely required. But not all changes in your applications will require coordination,
nor will they need to be synchronous. For these circumstances, Clojure also provides
another reference type, the Agent, that provides independent asynchronous changes,
which we’ll discuss next.
11.3
When to use Agents
Like all Clojure reference types, an Agent represents an identity, a specific thing whose
value can change over time. Each Agent has a queue to hold actions that need to be
performed on its value, and each action will produce a new value for the Agent to
hold and pass to the subsequent action. Thus the state of the Agent advances through
time, action after action, and by their nature only one action at a time can be operat-
ing on a given Agent. Of course, other actions can be operating on other Agents at
the same time, each in its own thread.
Download from Wow! eBook <www.wowebook.com>










248
CHAPTER 11 Mutation
You can queue an action on any Agent by using send or send-off, the minor differ-
ence between which we’ll discuss later. Agents are integrated with STM transactions,
and within a transaction any actions sent are held until the transaction commits or are
thrown away if the transaction retries. Thus send and send-off are not considered side-
effects in the context of a dosync, because they handle retries correctly and gracefully.
11.3.1 In-process versus distributed concurrency models
Both Clojure and Erlang are designed (Armstrong 2007) specifically with concurrent
programming in mind, and Erlang’s process2 model is similar in some ways to Clojure
Agents, so it’s fair to briefly compare how they each approach the problem.
Erlang takes a distributed, share-nothing (Armstrong 2007b) approach; Clojure
instead promotes shared, immutable data. The key to Clojure’s success is the fact that
its composite data structures are immutable, because immutable structures can be
freely shared among disparate threads. Erlang’s composite data structures are also
immutable, but because the communication model is distributed, the underlying
theme is always one of dislocation. The implications of this are that all knowledge of
the world under consideration is provided via messages. But with Clojure’s in-process
model, data structures are always accessible directly, as illustrated in figure 11.7,
whereas Erlang makes copies of the data sent back and forth between processes. This
works well for Erlang and allows it to provide its fault recovery guarantees, but many
application domains can benefit from the shared-memory model provided by Clojure.
The second difference is that Erlang messages block on reception, opening up the
possibility for deadlock. On the other hand, when interacting with Clojure Agents,
both sends and derefs proceed immediately and never block or wait on the Agent.
Clojure Agent
Erlang Actor
1
1
Agent
Actor
inc
inc
inc
inc
2
2
Agent
Actor
3
3
Agent
Actor
de
Figure 11.7 Clojure agents versus Erlang
deref
ref
get
get
processes: each Agent and process starts with
3
3
3
the value 1. Both receive an inc request
Actor
simultaneously but can only process one at a time,
resp
3
so more are queued. Requests to the process are
3
queued until a response can be delivered, whereas
Actor
resp
any number of simultaneous derefs can be done
on an Agent. Despite what this illustration may
3
suggest, an Agent is not just an actor with a hat on.
2
It’s interesting that popular opinion has tagged Erlang processes with the “actor” tag although the language
implementers rarely, if ever, use that term. Therefore, because the Erlang elite choose not to use that term,
we’ll avoid doing so also... almost.
Download from Wow! eBook <www.wowebook.com>
When to use Agents
249
Clojure does have an await function that can be used to block a thread until a partic-
ular Agent has processed a message, but this function is specifically disallowed in
Agent threads (and also STM transactions) in order to prevent accidentally creating
this sort of deadlock.
The final difference lies in the fact that Agents allow for arbitrary update func-
tions whereas Erlang processes are bound to static pattern-matched message han-
dling routines. In other words, pattern matching couples the data and update logic,
whereas the former decouples them. Erlang is an excellent language for solving the
extremely difficult problem of distributed computation, but Clojure’s concurrency
mechanisms service the in-process programming model more flexibly than Erlang
allows (Clementson 2008).
11.3.2 Controlling I/O with an Agent
One handy use for Agents is to serialize access to a resource, such as an file or other
I/O stream. For example, imagine we want to provide a way for multiple threads to report
their progress on various tasks, giving each report a unique incrementing number.
Because the state we want to hold is known, we can go ahead and create the Agent:
(def log-agent (agent 0))
Now we’ll supply an action function to send to log-agent. All action functions take as
their first argument the current state of the Agent and can take any number of other
arguments that are sent:
(defn do-log [msg-id message]
(println msg-id ":" message)
(inc msg-id))
Here msg-id is the state—the first time do-log is sent to the Agent, msg-id will be 0.
The return value of the action function will be the new Agent state, incrementing it to
1 after that first action.
Now we need to do some work worth logging about, but for this example we’ll just
pretend:
(defn do-step [channel message]
(Thread/sleep 1)
(send-off log-agent do-log (str channel message)))
(defn three-step [channel]
(do-step channel " ready to begin (step 0)")
(do-step channel " warming up (step 1)")
(do-step channel " really getting going now (step 2)")
(do-step channel " done! (step 3)"))
To see how log-agent will correctly queue and serialize the messages, we need to start
a few threads, each yammering away at the Agent, shown next:
(defn all-together-now []
(dothreads! #(three-step "alpha"))
(dothreads! #(three-step "beta"))
(dothreads! #(three-step "omega")))
Download from Wow! eBook <www.wowebook.com>
250
CHAPTER 11 Mutation
(all-together-now)
; 0 : alpha ready to being (step 0)
; 1 : omega ready to being (step 0)
; 2 : beta ready to being (step 0)
; 3 : alpha warming up (step 1)
; 4 : alpha really getting going now (step 2)
; 5 : omega warming up (step 1)
; 6 : alpha done! (step 3)
; 7 : omega really getting going now (step 2)
; 8 : omega done! (step 3)
; 9 : beta warming up (step 1)
; 10 : beta really getting going now (step 2)
; 11 : beta done! (step 3)
Your output is likely to look different, but one thing that should be exactly the same is
the stable, incrementing IDs assigned by the Agent, even while the alpha, beta, and
omega threads fight for control.
There are several other possible approaches to solving this problem, and it can be
constructive to contrast them. The simplest alternative would be to hold a lock while
printing and incrementing. Besides the general risk of deadlocks when a complex
program has multiple locks, there are some specific drawbacks even if this would be
the only lock in play. For one, each client thread would block anytime there was con-
tention for the lock, and unless some fairness mechanism were used, there’d be at
least a slight possibility of one or more threads being “starved” and never having an
opportunity to print or proceed with their work. Because Agent actions are queued
and don’t block waiting for their action to be processed, neither of these is a concern.
Another option would be to use a blocking queue to hold pending log messages.
Client threads would be able to add messages to the queue without blocking and with
adequate fairness. But you’d generally need to dedicate a thread to popping messages
from the queue and printing them, or write code to handle starting and stopping the
printing thread as needed. Why write such code when Agents do this for you already?
When no actions are queued, the Agent in our example has no thread assigned to it.3
Agents have other features that may or may not be useful in any given situation.
One is that the current state of an Agent can be observed cheaply. In the previous
example, this would allow us to discover the ID of the next message to be written out,
as follows:
@log-agent
;=> 11
Here the Agent is idle—no actions are queued or running, but the same expression
would work equally well if the Agent were running.
Other features include the await and await-for functions, which allow a sending
thread to block until all the actions it’s sent to a given set of Agents have completed.
3
Using Agents for logging might not be appropriate in all cases. For example, in probing scenarios, the num-
ber of log events could be extremely high. Coupling this volume with serialization could make the Agent
unable to catch its ever-growing queue.
Download from Wow! eBook <www.wowebook.com>


When to use Agents
251
This could be useful in this logging example if we wanted to be sure a particular mes-
sage had been written out before proceeding:
(do-step "important: " "this must go out")
(await log-agent)
The await-for function is similar but allows you to specify a number of milliseconds
after which to time out, even if the queued actions still haven’t completed.
A final feature Agents provide is that the set of actions you can send to an Agent is
open. You can tell an Agent to do something that wasn’t even conceived of at the time
the Agent was designed. For example, we could tell the Agent to skip ahead several
IDs, and this action would be queued up along with all the log-message actions and
executed by the Agent when its turn came:
(send log-agent (fn [_] 1000))
(do-step "epsilon " "near miss")
; 1000 : epsilon near miss
This is another area in which Clojure allows you to extend your design on the fly
instead of requiring recompiling or even restarting your app. If you’re paying atten-
tion, you might wonder why we used send in that last example rather than send-off.
11.3.3 The difference between send and send-off
You can use either send or send-off with any Agent. When you use send-off as we
did in most of the examples so far, only a single action queue is involved: the one man-
aged by the individual Agent. Anytime the Agent has a send-off action queued, it has
a thread assigned to it, working through the queue. With send, there’s a second
queue—actions still go into the Agent’s queue, but then the Agent itself queues up
waiting for a thread from a fixed-sized pool of threads. The size of this fixed pool is
based on the number of processors the JVM is running on, so it’s a bad idea to use
send with any actions that might block, tying up one of these limited number of
threads. These differences are illustrated in figure 11.8.
Idle agent. Empty queue,
no thread assigned.
Action queue
Unbounded
thread
send-off
pool
New agent state becomes
action applied to old state.
Figure 11.8 Agents using send versus send-off. When
Action queue
send
an Agent is idle, no CPU resources are being consumed.
Agent
queue
Each action is sent to an Agent using either send or
send-off, which determines which thread pool will be
The limited number of
used to dequeue and apply the action. Because actions
threads distribute CPU time
fairly among the queued
queued with send are applied by a limited thread pool, the
Bounded
agents.
thread
Agents queue up for access to these threads, a constraint
pool
that doesn’t apply to actions queued with send-off.
Download from Wow! eBook <www.wowebook.com>
252
CHAPTER 11 Mutation
We can make this scenario play out if we make a gaggle of Agents and send them
actions that sleep for a moment. Here’s a little function that does this, using which-
ever send function we specify, and then waits for all the actions to complete:
(defn exercise-agents [send-fn]
(let [agents (map #(agent %) (range 10))]
(doseq [a agents]
(send-fn a (fn [_] (Thread/sleep 1000))))
(doseq [a agents]
(await a))))
If we use send-off, all the agents will begin their one-second wait more or less simul-
taneously, each in its own thread. So the entire sequence of them will complete in
slightly over one second:
(time (exercise-agents send-off))
; "Elapsed time: 1008.771296 msecs"
Now we can demonstrate why it’s a bad idea to mix send with actions that block:
(time (exercise-agents send))
; "Elapsed time: 3001.555086 msecs"
The exact elapsed time you’ll see will depend on the number of processors you have,
but if you have fewer than eight you’ll see this example takes at least two seconds to
complete. The threads in the fixed-size pool are all clogged up waiting for sleep to
finish, so the other Agents queue up waiting for a free thread. Because clearly the
computer could complete all 10 actions in about one second using send-off, using
send is a bad idea.
So that’s it: send is for actions that stay busy using the processor and not blocking
on I/O or other threads, whereas send-off is for actions that might block, sleep, or
otherwise tie up the thread. This is why we used send-off for the threads that printed
log lines and send for the one that did no I/O at all.
11.3.4 Error handling
We’ve been fortunate so far—none of these Agent actions have thrown an exception.
But real life is rarely so kind. Most of the other reference types are synchronous and
so exceptions thrown while updating their state bubble up the call stack in a normal
way, to be caught with a regular try/catch in your application (or not). Because
Agent actions run in other threads after the sending thread has moved on, we need a
different mechanism for handling exceptions that are thrown by Agent actions. As of
Clojure 1.2, you can choose between two different error-handling modes for each
Agent: :continue and :fail.
:FAIL
By default, new Agents start out using the :fail mode, where an exception thrown by
an Agent’s action will be captured by the Agent and held so that you can see it later.
Meanwhile, the Agent will be considered failed or stopped and will stop processing its
Download from Wow! eBook <www.wowebook.com>
When to use Agents
253
action queue—all the queued actions will have to wait patiently until someone clears
up the Agent’s error.
One common mistake when dealing with Agents is to forget that your action func-
tion must take at least one argument for the Agent’s current state. For example, we
might try to reset the log-agent’s current message ID like this:
(send log-agent (fn [] 2000)) ; incorrect
@log-agent
;=> 1001
At first glance it looks like the action we sent had no effect, or perhaps hasn’t been
applied yet. But we’d wait in vain for that Agent to do anything ever again without
intervention, because it’s stopped. One way to determine this is with the agent-error
function:
(agent-error log-agent)
;=> #<IllegalArgumentException java.lang.IllegalArgumentException:
; Wrong number of args passed to: user$eval--509$fn>
This returns the error of a stopped Agent, or nil if it’s still running fine. Another way
to see whether an Agent is stopped is to try to send another action to it:
(send log-agent (fn [_] 3000))
; java.lang.RuntimeException: Agent is failed, needs restart
Even though this action would’ve worked fine, the Agent has failed and so no further
sends are allowed. The state of log-agent remains unchanged:
@log-agent
;=> 1001
In order to get the Agent back into working order, we need to restart it:
(restart-agent log-agent 2500 :clear-actions true)
;=> 2500
This resets the value of log-agent to 2500 and deletes all those actions patiently wait-
ing in their queue. If we hadn’t included the :clear-actionstrue option, those
actions would’ve survived and the Agent would continue processing them. Either way,
the Agent is now in good working order again, and so we can again send and send-
off to it:
(send-off log-agent do-log "The agent, it lives!")
; 2500 : The agent, it lives!
;=> #<Agent@72898540: 2500>
Note that restart-agent only makes sense and thus is only allowed when the Agent
has failed. If it hasn’t failed, any attempt to restart it throws an exception in the thread
making the attempt, and the Agent is left undisturbed:
(restart-agent log-agent 2500 :clear-actions true)
;=> java.lang.RuntimeException: Agent does not need a restart
Download from Wow! eBook <www.wowebook.com>
254
CHAPTER 11 Mutation
This mode is perhaps most appropriate for manual intervention. Agents that normally
don’t have errors but in a running system end up failing can use the :fail mode to
keep from doing anything too bad until a human can take things in hand, check to
see what happened, choose an appropriate new state for the Agent, and restart it just
as we did here.
:CONTINUE
The other error mode that Agents currently support is :continue, where any action
that throws an exception is skipped and the Agent proceeds to the next queued action
if any. This is most useful when combined with an error handler—if you specify an
:error-handler when you create an Agent, that Agent’s error mode defaults to
:continue. The Agent calls the error handler when an action throws an exception
and doesn’t proceed to the next action until the handler returns. This gives the han-
dler a chance to report the error in some appropriate way. For example, we could
have log-agent handle faulty actions by logging the attempt:
(defn handle-log-error [the-agent the-err]
(println "An action sent to the log-agent threw " the-err))
(set-error-handler! log-agent handle-log-error)
(set-error-mode! log-agent :continue)
With the error mode and handler set up, sending faulty actions does cause reports to
be printed as we wanted:
(send log-agent (fn [x] (/ x 0))) ; incorrect
; An action sent to the log-
agent threw java.lang.ArithmeticException: Divide by zero
;=> #<Agent@66200db9: 2501>
(send log-agent (fn [] 0)) ; also incorrect
; An action sent to the log-agent threw java.lang.IllegalArgumentException:
; Wrong number of args passed to: user$eval--820$fn
;=> #<Agent@66200db9: 2501>
And the Agent stays in good shape, always ready for new actions to be sent:
(send-off log-agent do-log "Stayin' alive, stayin' alive...")
; 2501 : Stayin' alive, stayin' alive...
Note that error handlers can’t change the state of the Agent (ours keeps its current
message id of 2501 throughout the preceding tests). Error handlers are also sup-
ported in the :fail error mode, but handlers can’t call restart-agent so they’re less
often useful for :fail than they are for the :continue error mode.
11.3.5 When not to use Agents
It can be tempting to repurpose Agents for any situation requiring the spawning of
new threads. Their succinct syntax and “Clojurey” feel often make this temptation
strong. But though Agents perform beautifully when each one is representing a real
identity in your application, they start to show weaknesses when used a sort of “green
thread” abstraction. In cases where you just need a bunch of worker threads banging
Download from Wow! eBook <www.wowebook.com>
When to use Atoms
255
away on some work, or you have a specific long-running thread polling or blocking on
events, or any other kind of situation where it doesn’t seem useful that the Agent
maintain a value, you’ll usually be able to find a better mechanism than Agents. In
these cases, there’s every reason to consider using a Java Thread directly, or a Java
executor (as we did with dothreads!) to manage a pool of threads, or in some cases
perhaps a Clojure future.
Another common temptation is to use Agents when you need state held but you
don’t actually want the sending thread to proceed until the Agent action you sent is
complete. This can be done by using await, but it’s another form of abuse that should
be avoided. For one, because you’re not allowed to use await in an Agent’s action, as
you try to use this technique in more and more contexts you’re likely to run into a sit-
uation where it won’t work. But in general, there’s probably a reference type that will
do a better job of behaving the way you want. Because this is essentially an attempt to
use Agents as if they were synchronous, you may have more success with one of the
other shared synchronous types. In particular, Atoms are shared and uncoordinated
just like Agents, but they’re synchronous and so may fit better.
11.4
When to use Atoms
Atoms are like Refs in that they’re synchronous but are like Agents in that they’re inde-
pendent (uncoordinated). An Atom may seem at first glance similar to a variable, but
as we proceed you’ll see that any similarities are at best superficial. The use cases for
Atoms are similar to those of compare-and-swap ( CAS ) spinning operations. Anywhere
you might want to atomically compute a value given an existing value and swap in the
new value, an Atom will suffice. Atom updates occur locally to the calling thread, and
execution continues after the Atom value has been changed. If another thread B
changes the value in an Atom before thread A is successful, then A retries. But these
retries are spin-loop and don’t occur within the STM, and thus Atom changes can’t be
coordinated with changes to other reference types. You should take care when embed-
ding changes to Atoms within Clojure’s transactions because as you know, transactions
can potentially be retried numerous times. Once an Atom’s value is set, it’s set, and it
doesn’t roll back when a transaction is retried, so in effect this should be viewed as a
side effect. Therefore, use Atoms in transactions only when you’re certain that an
attempt to update its value, performed numerous times, is idempotent.
Aside from the normal use of @ and deref to query an Atom’s value, you can also
use the mutating functions swap!, compare-and-set!, and reset!.
11.4.1 Sharing across threads
As we mentioned, Atoms are thread safe and can be used when you require a light-
weight mutable reference to be shared across threads. A simple case is one of a glob-
ally accessible incrementing timer created using the atom function:
(def *time* (atom 0))
(defn tick [] (swap! *time* inc))
(dothreads! tick :threads 1000 :times 100)
Download from Wow! eBook <www.wowebook.com>
256
CHAPTER 11 Mutation
@*time*
;=> 100000
Though this will work, Java already provides a concurrent class for just such a purpose,
java.util.concurrent.atomic.AtomicInteger, which can be used similarly:
(def *time* (java.util.concurrent.atomic.AtomicInteger. 0))
(defn tick [] (.getAndIncrement *time*))
(dothreads! tick :threads 1000 :times 100)
*time*
;=> 100000
Though the use of AtomicInteger is more appropriate in this case, the use of an
Atom works to show that it’s safe to use across threads.
11.4.2 Using Atoms in transactions
Just because we said that Atoms should be used carefully within transactions, that’s not
to say that they can never be used in that way. In fact, the use of an Atom as the refer-
ence holding a function’s memoization cache is idempotent on update.
MEMOIZATION Memoization is a way for a function to store calculated values in
a cache so that multiple calls to the function can retrieve previously calcu-
lated results from the cache, instead of performing potentially expensive cal-
culations every time. Clojure provides a core function memoize that can be
used on any referentially transparent function.
Individual requirements from memoization are highly personal, and a generic
approach isn’t always the appropriate solution for every problem. We’ll discuss per-
sonalized memoization strategies in section 12.4, but for now we’ll use an illustrative
example appropriate for Atom usage.
ATOMIC MEMOIZATION
The core memoize function is great for creating simple function caches, but it has
some limitations. First, it doesn’t allow for custom caching and expiration strategies.
Additionally, memoize doesn’t allow you to manipulate the cache for the purposes of
clearing it in part or wholesale. Therefore, we’ll create a function manipulable-
memoize that allows us to get at the cache and perform operations on it directly.
Throughout the book, we’ve mentioned Clojure’s metadata facility, and for this exam-
ple it will come in handy. We can take in the function to be memoized and attach
some metadata4 with an Atom containing the cache itself for later manipulation.
Listing 11.3 A resettable memoize function
(defn manipulable-memoize [function]
(let [cache (atom {})]
Store cache
(with-meta
in Atom
(fn [& args]
4 The ability to attach metadata to functions is a recent addition to Clojure version 1.2.
Download from Wow! eBook <www.wowebook.com>
When to use Atoms
257
(or (second (find @cache args))
Check cache first
(let [ret (apply function args)]
Else calculate,
(swap! cache assoc args ret)
store, and return
ret)))
{:cache cache})))
Attach metadata
As shown in listing 11.3, we’ve slightly modified the core memoize function to attach
the Atom to the function being memoized. You can now observe manipulable-
memoize in action:
(def slowly (fn [x] (Thread/sleep 3000) x))
(time [(slowly 9) (slowly 9)])
; "Elapsed time: 6000.63 msecs"
;=> [9 9]
(def sometimes-slowly (manipulable-memoize slowly))
(time [(sometimes-slowly 108) (sometimes-slowly 108)])
; "Elapsed time: 3000.409 msecs"
;=> [108 108]
The call to slowly is always... well... slow, as you’d expect. But the call to sometimes-
slowly is only slow on the first call given a certain argument. This too is just as you’d
expect. Now we can inspect sometimes-slowly’s cache and perform some operations
on it:
(meta sometimes-slowly)
;=> {:cache #<Atom@e4245: {(108) 108}>}
(let [cache (:cache (meta sometimes-slowly))]
(swap! cache dissoc '(108)))
;=> {}
You may wonder why we used swap! to dissoc the cached argument 108 instead of
using (reset! cache {}). There are certainly valid use cases for the wholesale reset
of an Atom’s value, and this case is arguably one. But it’s good practice to set your ref-
erence values via the application of a function rather than the in-place value setting.
In this way, you can be more selective about the value manipulations being per-
formed. Having said that, here are the consequences our actions had:
(meta sometimes-slowly)
;=> {:cache #<Atom@e4245: {}>}
(time (sometimes-slowly 108))
; "Elapsed time: 3000.3 msecs"
;=> 108
And yes, you can see that we were able to remove the cached argument value 108
using the metadata map attached to the function sometimes-slowly. There are better
ways to allow for pointed cache removal than this, but for now you can take heart in
that using an Atom, we’ve allowed for the local mutation of a reference in a thread-
safe way. Additionally, because of the nature of memoization, you can use these
memoized functions in a transaction without ill effect. Bear in mind that if you do use
this in a transaction, then any attempt to remove values from the cache may not be
Download from Wow! eBook <www.wowebook.com>
258
CHAPTER 11 Mutation
met with the results expected. Depending on the interleaving of your removal and any
restarts, the value(s) you remove might be reinserted on the next time through the
restart. But even this condition is agreeable if your only concern is reducing total
cache size.
11.5
When to use locks
Clojure’s reference types and parallel primitives cover a vast array of use cases. Addi-
tionally, Java’s rich set of concurrency classes found in the java.util.concurrent
package are readily available. But even with this arsenal of tools at your disposal, there
still may be circumstances where explicit locking is the only option available, the com-
mon case being the modification of arrays concurrently. We’ll start with a simple pro-
tocol to describe a concurrent, mutable, safe array that holds an internal array
instance, allowing you to access it or mutate it safely. A naive implementation can be
seen in the following listing.
Listing 11.4 A simple SafeArray protocol
(ns joy.locks
(:refer-clojure :exclude [aget aset count seq])
(:require [clojure.core :as clj]))
(defprotocol SafeArray
Small set
(aset [this i f])
of functions
(aget [this i])
(count [this])
(seq [this]))
(defn make-dumb-array [t sz]
(let [a (make-array t sz)]
(reify
SafeArray
(count [_] (clj/count a))
(seq [_] (clj/seq a))
aget and aset
(aget [_ i] (clj/aget a i))
are unguarded
(aset [this i f]
(clj/aset a i (f (aget this i)))))))