Document Outline
JoyOfClojure
brief contents
contents
foreword
preface
acknowledgments
Fogus
Chouser
about this book
Why learn Clojure?
Who should read this book?
Roadmap
Foundations
Data types
Functional programming
Large-scale design
Tangential considerations
Code conventions
Getting Clojure
Prerequisites
Instructions
REPL
Downloading code examples
Author Online
About the cover illustration
Foundations
Chapter 1 Clojure philosophy
1.1 The Clojure way
1.1.1 Simplicity
1.1.2 Freedom to focus
1.1.3 Empowerment
1.1.4 Clarity
1.1.5 Consistency
1.2 Why a(nother) Lisp?
1.2.1 Beauty
1.2.2 Extreme flexibility
1.2.3 Code is data
1.3 Functional programming
1.3.1 A workable definition of functional programming
1.3.2 The implications of functional programming
1.4 Why Clojure isn’t especially object-oriented
1.4.1 Defining terms
1.4.2 Imperative “baked in”
1.4.3 Most of what OOP gives you, Clojure provides
Polymorphism and the expression problem
Subtyping and interface-oriented programming
Encapsulation
Not everything is an object
1.5 Summary
Chapter 2 Drinking from the Clojure firehose
2.1 Scalars
2.1.1 Numbers
2.1.2 Integers
2.1.3 Floating-point numbers
2.1.4 Rationals
2.1.5 Symbols
2.1.6 Keywords
2.1.7 Strings
2.1.8 Characters
2.2 Putting things together: collections
2.2.1 Lists
2.2.2 Vectors
2.2.3 Maps
2.2.4 Sets
2.3 Making things happen: functions
2.3.1 Calling functions
2.3.2 Defining functions
2.3.3 Simplifying function definitions with def and defn
2.3.4 In-place functions with #()
2.4 Vars
2.4.1 Declaring bindings using def
2.5 Locals, loops, and blocks
2.5.1 Blocks
2.5.2 Locals
2.5.3 Loops
recur
loop
Tail position
2.6 Preventing things from happening: quoting
2.6.1 Evaluation
2.6.2 Quoting
Syntax-quote
Symbol auto-qualification
2.6.3 Unquote
2.6.4 Unquote-splicing
2.6.5 Auto-gensym
2.7 Leveraging Java via interop
2.7.1 Accessing static class members
2.7.2 Creating Java class instances
2.7.3 Accessing Java instance members with the . operator
2.7.4 Setting Java instance properties
2.7.5 The .. macro
2.7.6 The doto macro
2.7.7 Defining classes
2.8 Exceptional circumstances
2.8.1 A little pitch and catch
2.9 Namespaces
2.9.1 Creating namespaces using ns
2.9.2 Loading other namespaces with :require
2.9.3 Loading and creating mappings with :use
2.9.4 Creating mappings with :refer
2.9.5 Loading Java classes with :import
2.10 Summary
Chapter 3 Dipping our toes in the pool
3.1 Truthiness
3.1.1 What’s truth?
3.1.2 Don’t create Boolean objects
3.1.3 nil versus false
3.2 Nil pun with care
3.3 Destructuring
3.3.1 Your assignment, should you choose to accept it
3.3.2 Destructuring with a vector
3.3.3 Destructuring with a map
Associative destructuring
3.3.4 Destructuring in function parameters
3.3.5 Destructuring versus accessor methods
3.4 Using the REPL to experiment
3.4.1 Experimenting with seqs
3.4.2 Experimenting with graphics
3.4.3 Putting it all together
3.4.4 When things go wrong
3.4.5 Just for fun
3.5 Summary
Data types
Chapter 4 On scalars
4.1 Understanding precision
4.1.1 Truncation
4.1.2 Promotion
4.1.3 Overflow
4.1.4 Underflow
4.1.5 Rounding errors
4.2 Trying to be rational
4.2.1 Why be rational?
4.2.2 How to be rational
4.2.3 Caveats of rationality
4.3 When to use keywords
4.3.1 How are keywords different from symbols?
As Keys
As Enumerations
As Multimethod Dispatch Values
As Directives
4.3.2 Qualifying your keywords
4.4 Symbolic resolution
4.4.1 Metadata
4.4.2 Symbols and namespaces
4.4.3 Lisp-1
4.5 Regular expressions—the second problem
4.5.1 Syntax
4.5.2 Functions
4.5.3 Beware of mutable matchers
4.6 Summary
Chapter 5 Composite data types
5.1 Persistence, sequences, and complexity
5.1.1 “You keep using that word. I do not think it means what you think it means.”
5.1.2 Sequence terms and what they mean
Terms
Equality partitions
The sequence abstraction
5.1.3 Big-O
5.2 Vectors: creating and using them in all their varieties
5.2.1 Building vectors
Primitive vectors
5.2.2 Large vectors
5.2.3 Vectors as stacks
5.2.4 Using vectors instead of reverse
5.2.5 Subvectors
5.2.6 Vectors as MapEntries
5.2.7 What vectors aren’t
Vectors aren’t sparse
Vectors aren’t queues
Vectors aren’t sets
5.3 Lists: Clojure’s code form data structure
5.3.1 Lists like Lisps like
5.3.2 Lists as stacks
5.3.3 What lists aren’t
5.4 How to use persistent queues
5.4.1 A queue about nothing
5.4.2 Putting things on
5.4.3 Getting things
5.4.4 Taking things off
5.5 Persistent sets
5.5.1 Basic properties of Clojure sets
How Clojure populates sets
5.5.2 Keeping your sets in order with sorted-set
5.5.3 contains?
5.5.4 clojure.set
Intersection
Union
Difference
5.6 Thinking in maps
5.6.1 Hash maps
5.6.2 Keeping your keys in order with sorted maps
5.6.3 Keeping your insertions in order with array maps
5.7 Putting it all together: finding the position of items in a sequence
5.7.1 Implementation
5.8 Summary
Functional programming
Chapter 6 Being lazy and set in your ways
6.1 On immutability
6.1.1 Defining immutability
Every day is like Sunday
Immutability through convention
6.1.2 Being set in your ways—immutability
Invariants
Reasoning
Equality has meaning
Sharing is cheap
Flattening the levels of indirection
Immutability fosters concurrent programming
6.2 Designing a persistent toy
6.3 Laziness
6.3.1 Familiar laziness with logical-and
6.3.2 Understanding the lazy-seq recipe
Utilizing lazy-seq and rest
6.3.3 Losing your head
6.3.4 Employing infinite sequences
6.3.5 The delay and force macros
6.4 Putting it all together: a lazy quicksort
The implementation
6.5 Summary
Chapter 7 Functional programming
7.1 Functions in all their forms
7.1.1 First-class functions
Creating functions on demand using composition
Creating functions on demand using partial functions
Reversing truth with complement
Using functions as data
7.1.2 Higher-order functions
Functions as arguments
Functions as return values
7.1.3 Pure functions
Referential transparency
Optimization
Testability
7.1.4 Named arguments
7.1.5 Constraining functions with pre- and postconditions
Decoupling assertions from functions
7.2 Closures
Functions returning closures
Closing over parameters
Passing closures as functions
Sharing closure context
Compile-time versus run-time
7.3 Thinking recursively
7.3.1 Mundane recursion
Regular recursion is fun again with lazy-seq
7.3.2 Tail calls and recur
Generalized tail-call optimization
Tail recursion
Why recur?
7.3.3 Don’t forget your trampoline
7.3.4 Continuation-passing style
7.4 Putting it all together: A* pathfinding
The world
Neighbors
7.4.1 The A* implementation
7.4.2 Notes about the A* implementation
7.5 Summary
Large-scale design
Chapter 8 Macros
8.1 Data is code is data
8.1.1 Syntax-quote, unquote, and splicing
8.1.2 Macro rules of thumb
8.2 Defining control structures
8.2.1 Defining control structures without syntax-quote
8.2.2 Defining control structures using syntax-quote and unquoting
8.3 Macros combining forms
8.4 Using macros to change forms
8.5 Using macros to control symbolic resolution time
8.5.1 Anaphora
8.5.2 (Arguably) useful selective name capturing
8.6 Using macros to manage resources
8.7 Putting it all together: macros returning functions
8.8 Summary
Chapter 9 Combining data and code
9.1 Namespaces
9.1.1 Creating namespaces
ns
in-ns
create-ns
9.1.2 Expose only what’s needed
9.1.3 Declarative inclusions and exclusions
9.2 Exploring Clojure multimethods with the Universal Design Pattern
9.2.1 The parts
beget
put
get
9.2.2 Usage
No notion of self
9.2.3 Multimethods to the rescue
9.2.4 Ad hoc hierarchies for inherited behaviors
9.2.5 Resolving conflict in hierarchies
9.2.6 Arbitrary dispatch for true maximum power
9.3 Types, protocols, and records
9.3.1 Records
9.3.2 Protocols
Sharing method implementations
Reify
Namespaced methods
Method implementations in defrecord
9.3.3 Building from a more primitive base with deftype
9.4 Putting it all together: a fluent builder for chess moves
9.4.1 Java implementation
9.4.2 Clojure implementation
Using records
Separation of concerns
9.5 Summary
Chapter 10 Java.next
10.1 Generating objects on the fly with proxy
10.1.1 A simple dynamic web service
It’s called proxy for a reason
Proxies for true power dynamism
Proxies as proper citizens
Final points about proxy
10.2 Clojure gen-class and GUI programming
10.2.1 Namespaces as class specifications
The guts of namespace compilation
10.2.2 Exploring user interface design and development with Clojure
10.3 Clojure’s relationship to Java arrays
10.3.1 Types of arrays: primitive and reference
Creating primitive arrays
Creating reference arrays
10.3.2 Array mutability
10.3.3 That unfortunate naming convention
10.3.4 Multidimensional arrays
10.3.5 Variadic method/constructor calls
10.4 All Clojure functions implement...
10.4.1 java.util.Comparator
10.4.2 java.lang.Runnable
10.4.3 java.util.concurrent.Callable
10.5 Using Clojure data structures in Java APIs
10.5.1 java.util.List
10.5.2 java.lang.Comparable
10.5.3 java.util.RandomAccess
10.5.4 java.util.Collection
java.util.Map
10.5.5 java.util.Set
10.6 definterface
10.6.1 Generating interfaces on the fly
10.7 Be wary of exceptions
10.7.1 A bit of background regarding exceptions
10.7.2 Runtime versus compile-time exceptions
Runtime exceptions
Compile-time exceptions
10.7.3 Handling exceptions
10.7.4 Custom exceptions
10.8 Summary
Chapter 11 Mutation
11.1 Software transactional memory with multiversion concurrency control and snapshot isolation
Software transactional memory
11.1.1 Transactions
11.1.2 Embedded transactions
11.1.3 The things that STM makes easy
Consistent information
No need for locks
ACI
11.1.4 Potential downsides
Write skew
Live-lock
11.1.5 The things that make STM unhappy
I/O
Class instance mutation
Large transactions
11.2 When to use Refs
11.2.1 Coordinated, synchronous change using alter
11.2.2 Commutative change with commute
11.2.3 Vulgar change with ref-set
11.2.4 Fixing write-skew with ensure
11.2.5 Refs under stress
11.3 When to use Agents
11.3.1 In-process versus distributed concurrency models
11.3.2 Controlling I/O with an Agent
11.3.3 The difference between send and send-off
11.3.4 Error handling
:fail
:continue
11.3.5 When not to use Agents
11.4 When to use Atoms
11.4.1 Sharing across threads
11.4.2 Using Atoms in transactions
Atomic memoization
11.5 When to use locks
11.5.1 Safe mutation through locking
References around evil mutable things
11.5.2 Using Java’s explicit locks
11.6 When to use futures
11.6.1 Futures as callbacks
Counting word occurrences in a set of Twitter feeds
11.7 When to use promises
11.7.1 Parallel tasks with promises
11.7.2 Callback API to blocking API
11.7.3 Deterministic deadlocks
11.8 Parallelism
11.8.1 pvalues
11.8.2 pmap
11.8.3 pcalls
11.9 Vars and dynamic binding
11.9.1 The binding macro
11.9.2 Creating a named Var
11.9.3 Creating anonymous Vars
11.9.4 Dynamic scope
11.10 Summary
Tangential considerations
Chapter 12 Performance
12.1 Type hints
12.1.1 Advantages of type adornment
12.1.2 Type-hinting arguments and returns
12.1.3 Type-hinting objects
12.2 Transients
12.2.1 Ephemeral garbage
12.2.2 Transients compare in efficiency to mutable collections
12.3 Chunked sequences
12.3.1 Regaining one-at-a-time laziness
12.4 Memoization
12.4.1 Re-examining memoization
12.4.2 A memoization protocol
12.5 Understanding coercion
12.5.1 First rule of coercion: don’t
12.5.2 Corollary: you’re probably not doing it right
12.5.3 Second rule of coercion: don’t
12.5.4 Third rule of coercion: coerce a stable local
12.5.5 Fourth rule of coercion: watch your sizes
12.5.6 Fifth rule of coercion: truncate only as a goal
12.6 Summary
Chapter 13 Clojure changes the way you think
13.1 DSLs
13.1.1 A ubiquitous DSL
13.1.2 Putting parentheses around the specification
defunits
13.1.3 A note about Clojure’s approach to DSLs
13.2 Testing
13.2.1 Some useful techniques
Using with-var-root to stub
clojure.test as specification
13.2.2 Contracts programming
Revisiting pre- and postconditions
Advantages of pre- and postconditions
13.3 A lack of design patterns
13.3.1 Clojure’s first-class design patterns
Observer
Strategy
Visitor
Abstract Factory
Interpreter
Builder
Façade
Iterator
Dependency injection
13.4 Error handling and debugging
13.4.1 Error handling
Dynamic tree traversal
13.4.2 Debugging
A breakpoint macro
Overriding the REPL’s reader
Overriding the REPL’s evaluator
Putting it all together
Multiple breakpoints and breakpoints in macros
13.5 Fare thee well
resources
Miscellaneous resources
Online resources
index
Keywords and symbols
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z