This chapter provides a quick tour of the bare necessities—the things you’ll need to know to understand the rest of this book. If you’ve been programming with Clojure for a while, this may be a review, but otherwise it should give you everything you need to start writing Clojure code. In most cases throughout this chapter, the examples provided will be perfunctory in order to highlight the immediate point. Later in the book we’ll build on these topics and many more, so don’t worry if you don’t quite grasp every feature now—you’ll get there.
Interaction with Clojure is often performed at the Read-Eval-Print Loop (REPL). When starting a new REPL session, you’re presented with a simple prompt:
user>
The user prompt refers to the top-level namespace of the default REPL. It’s at this point that Clojure waits for input expressions. Valid Clojure expressions consist of numbers, symbols, keywords, booleans, characters, functions, function calls, macros, strings, literal maps, vectors, and sets. Some expressions, such as numbers, strings, and keywords, are self-evaluating—when entered, they evaluate to themselves. The Clojure REPL also accepts source comments, which are marked by the semicolon ; and continue to a newline:
user> 42 ; numbers evaluate to themselves ;=> 42 user> "The Misfits" ; strings do too ;=> "The Misfits" user> :pyotr ; as do keywords ;=> :pyotr
Now that we’ve seen several scalar data types, we’ll take a closer look at each of them.
The Clojure language has a rich set of data types. Like most programming languages, it provides scalar types such as integers, strings, and floating-point numbers, each representing a single unit of data. Clojure provides several different categories of scalar data types: integers, floats, rationals, symbols, keywords, strings, characters, booleans, and regex patterns. In this section, we’ll address most of these[1] categories in turn, providing examples of each.
1 We won’t look at regular expression patterns here, but for details on everything regex-related you can flip forward to section 4.6.
A number can consist of only the digits 0-9, a decimal point (.), a sign (+ or -), and an optional e for numbers written in exponential notation. In addition to these elements, numbers in Clojure can take either octal or hexadecimal form and also include an optional M, that flags a number as a decimal requiring arbitrary precision: an important aspect of numbers in Clojure. In many programming languages, the precision[2] of numbers is restricted by the host platform, or in the case of Java and C#, defined by the language specification. Clojure on the other hand uses the host language’s primitive numbers when appropriate, but rolls over to the arbitrarily precise versions when needed, or when explicitly specified.
Integers comprise the whole number set, both positive and negative. Any number starting with an optional sign or digit followed exclusively by digits is considered and stored as an integer. Integers in Clojure can theoretically take an infinitely large value, although in practice the size is limited by the memory available. The following numbers are recognized by Clojure as integers:
42 +9 -107 991778647261948849222819828311491035886734385827028118707676848307166514
The following illustrates the use of decimal, hexadecimal, octal, radix-32, and binary literals, respectively, all representing the same number:
[127 0x7F 0177 32r3V 2r01111111] ;=> [127 127 127 127 127]
The radix notation supports up to base 36. Adding signs to the front of each of the integer literals is also legal.
Floating-point numbers are the decimal expansion of rational numbers. Like Clojure’s implementation of integers, the floating-point values are arbitrarily precise.[3] Floating-point numbers can take the traditional form of some number of digits and then a decimal point, followed by some number of digits. But floating-point numbers can also take an exponential form (scientific notation) where a significant part is followed by an exponent part separated by a lower or uppercase E. The following numbers are examples of valid floating-point numbers:
3 With some caveats, as we’ll discuss in section 4.1.
1.17 +1.22 -2. 366e7 32e-14 10.7e-3
Numbers are largely the same across most programming languages, so we’ll move on to some scalar types that are more unique to Lisp and Lisp-inspired languages.
Clojure provides a rational type in addition to integer and floating-point numbers. Rational numbers offer a more compact and precise representation of a given value over floating-point. Rationals are represented classically by an integer numerator and denominator, and that’s exactly how they’re represented in Clojure. The following numbers are examples of valid rational numbers:
22/7 7/22 1028798300297636767687409028872/88829897008789478784 -103/4
Something to note about rational numbers in Clojure is that they’ll be simplified if they can—the rational 100/4 will resolve to the integer 25.
Symbols in Clojure are objects in their own right, but are often used to represent another value. When a number or a string is evaluated, you get back exactly the same object, but when a symbol is evaluated, you’ll get back whatever value that symbol is referring to in the current context. In other words, symbols are typically used to refer to function parameters, local variables, globals, and Java classes.
Keywords are similar to symbols, except that they always evaluate to themselves. You’re likely to see the use of keywords far more in Clojure than symbols. The form of a keyword’s literal syntax is as follows:
:chumby :2 :? :ThisIsTheNameOfaKeyword
Although keywords are prefixed by a colon :, it’s only part of the literal syntax and not part of the name itself. We go into further detail about keywords in section 4.3.
Strings in Clojure are represented similarly to the way they’re used in many programming languages: a string is any sequence of characters enclosed within a set of double quotes, including newlines, as shown:
"This is a string"
"This is also a
String"
Both will be stored as written, but when printed at the REPL, multiline strings will include escapes for the literal newline characters like "This is also a\n String".
Clojure characters are written with a literal syntax prefixed with a backslash and are stored as Java Character objects, as shown:
\a ; The character lowercase a \A ; The character uppercase A \u0042 ; The unicode character uppercase B \\ ; The back-slash character \ \u30DE ; The unicode katakana character ?
And that’s it for Clojure’s scalar data types. In the next section, we’ll discuss Clojure’s collection data types, which is where the real fun begins.
We’ll cover the collection types in greater detail in chapter 5, but because Clojure programs are made up of various kinds of literal collections, it’s helpful to at least glance at the basics of lists, vectors, maps, and sets.
Lists are the classic collection type in List Processing languages, and Clojure is no exception. Literal lists are written with parentheses:
(yankee hotel foxtrot)
When a list is evaluated, the first item of the list—yankee in this case—will be resolved to a function, macro, or special form. If yankee is a function, the remaining items in the list will be evaluated in order, and the results will be passed to yankee as its parameters.
A form is any Clojure object meant to be evaluated, including but not limited to lists, vectors, maps, numbers, keywords, and symbols. A special form is a form with special syntax or special evaluation rules that are typically not implemented using the base Clojure forms. An example of a special form is the . (dot) operator used for Java interoperability purposes.
If on the other hand yankee is a macro or special form, the remaining items in the list aren’t necessarily evaluated, but are processed as defined by the macro or operator.
Lists can contain items of any type, including other collections. Here are some more examples:
(1 2 3 4) () (:fred ethel) (1 2 (a b c) 4 5)
Note that unlike some Lisps, the empty list in Clojure, written as (), isn’t the same as nil.
Like lists, vectors store a series of values. There are several differences described in section 5.4, but for now only two are important. First, vectors have a literal syntax using square brackets:
[1 2 :a :b :c]
The other important difference is that when evaluated, vectors simply evaluate each item in order. No function or macro call is performed on the vector itself, though if a list appears within the vector, that list is evaluated following the normal rules for a list. Like lists, vectors are type heterogeneous, and as you might guess, the empty vector [] isn’t the same as nil.
Maps store unique keys and one value per key—similar to what some languages and libraries call dictionaries or hashes. Clojure actually has several types of maps with different properties, but don’t worry about that for now. Maps can be written using a literal syntax with alternating keys and values inside curly braces. Commas are frequently used between pairs, but are just whitespace like they are everywhere else in Clojure:
{1 "one", 2 "two", 3 "three"}
Like vectors, every item in a map literal (each key and each value) is evaluated before the result is stored in the map. Unlike vectors, the order in which they’re evaluated isn’t guaranteed. Maps can have items of any type for both keys and values, and the empty map {} isn’t the same as nil.
Sets are probably the least common collection type that has a literal syntax. Sets store zero or more unique items. They’re written using curly braces with a leading hash:
#{1 2 "three" :four 0x5}
Again, the empty set #{} isn’t the same as nil.
That’s all for now regarding the basic collection types, but chapter 4 will cover in-depth the idiomatic uses of each, including their relative strengths and weaknesses.
Functions in Clojure are a first-class type, meaning that they can be used the same as any value. Functions can be stored in Vars, held in lists and other collection types, and passed as arguments to and even returned as the result of other functions.
Clojure borrows its function calling conventions from Lisp, also known as prefix notation:
(+ 1 2 3) ;=> 6
The immediately obvious advantage of prefix over infix notation used by C-style languages[4] is that the former allows any number of operands per operator, whereas infix allows only two. Another, less obvious advantage to structuring code as prefix notation is that it completely eliminates the problem of operator precedence. Clojure makes no distinction between operator notation and regular function calls—all Clojure constructs, functions, macros, and operators are formed using prefix, or fully parenthesized, notation. This uniform structure forms the basis for the incredible flexibility that Lisp-like languages provide.
4 Of course, Java uses infix notation in only a few instances. The remainder of the language forms tend toward C-style ad hoc debauchery.
An anonymous (unnamed) Clojure function can be defined as a special form. A special form is a Clojure expression that’s part of the core language, but not created in terms of functions, types, or macros.
An example of a function taking two elements that returns a set of those elements would be defined as
(fn mk-set [x y] #{x y})
;=> #<user$eval__1$mk_set__2 user$eval__1$mk_set__2@d3576a2>
Entering this function definition in a Clojure REPL gives us a seemingly strange result. This is because the REPL is showing its internal name for the function object returned by the fn special form. This is far from satisfying, given that now that the function has been defined, there’s no apparent way to execute it. It should be noted that the mk-set symbol is optional and doesn’t correspond to a globally accessible name for the function, but instead to a name internal to the function itself used for self-calls. Recall from the previous section that the function call form is always (some-function arguments):
((fn [x y] #{x y}) 1 2)
;=> #{1 2}
The second form to define functions allows for arity overloading of the invocations of a function. Arity refers to the differences in the argument count that a function will accept. Changing our previous simple set-creating function to accept either one or two arguments would be represented as
(fn
([x] #{x})
([x y] #{x y}))
The difference from the previous form is that we can now have any number of argument/body pairs as long as the arity of the arguments differ. Naturally, the execution of such a function for one argument would be
((fn
([x] #{x})
([x y] #{x y})) 42)
;=> #{42}
As you saw, arguments to functions are bound one-for-one to symbols during the function call, but there is a way for functions to accept a variable[5] number of arguments:
5 The implementation details of Clojure prevent the creation of functions with an arity larger than 20, but in practice this should rarely, if ever, be an issue.
((fn arity2 [x y] [x y]) 1 2 3) ;=> java.lang.IllegalArgumentException: Wrong number of args passed
Clearly, calling the arity2 function with three arguments won’t work. But what if we wanted it to take any number of arguments? The way to denote variable arguments is to use the & symbol followed by a symbol. Every symbol in the arguments list before the & will still be bound one-for-one to the same number of arguments passed during the function call. But any additional arguments will be aggregated in a sequence bound to the symbol following the & symbol:
((fn arity2+ [x y & z] [x y z]) 1 2) ;=> [1 2 nil] ((fn arity2+ [x y & z] [x y z]) 1 2 3 4) ;=> [1 2 (3 4)] ((fn arity2+ [x y & z] [x y z]) 1) ;=> java.lang.IllegalArgumentException: Wrong number of args passed
Of course, arity2+ still requires at least two arguments. But this isn’t satisfactory, as it quickly becomes clear that to write programs using only this form would be cumbersome, repetitive, and overly verbose. Thankfully, Clojure provides another, more convenient form to create named functions.
The def special form is a way to assign a symbolic name to a piece of Clojure data. Clojure functions are first-class; they’re equal citizens with data, allowing assignment to Vars, storage in collections, and as arguments to (or returned from) other functions. This is different from programming languages where functions are functions and data are data, and there’s a world of capability available to the latter that’s incongruous to the former.
Therefore, in order to associate a name with our previous function using def, we’d use
(def make-a-set
(fn
([x] #{x})
([x y] #{x y})))
And we could now call it in a more intuitive way:
(make-a-set 1)
;=> #{1}
(make-a-set 1 2)
;=> #{1 2}
There’s another way to define functions in Clojure using the defn macro. While certainly a much nicer way to define and consequently refer to functions by name, using def as shown is still cumbersome to use. Instead, the simplest defn syntax is a convenient and concise way to create named functions that looks similar to the original fn form, and allow an additional documentation string:
(defn make-a-set
"Takes either one or two values and makes a set from them"
([x] #{x})
([x y] #{x y}))
The function can again be called the same as we saw before.
Clojure provides a shorthand notation for creating an anonymous function using the #() reader feature. In a nutshell, reader features are analogous to preprocessor directives in that they signify that some given form should be replaced with another at read time. In the case of the #() form, it’s effectively replaced with the special form fn. In fact, anywhere that it’s appropriate to use #(), it’s likewise appropriate for the fn special form.
The #() form can also accept arguments that are implicitly declared through the use of special symbols prefixed with %:
(def make-a-list_ #(list %)) (def make-a-list1 #(list %1)) (def make-a-list2 #(list %1 %2)) (def make-a-list3 #(list %1 %2 %3)) (def make-a-list3+ #(list %1 %2 %3 %&)) (make-a-list_ 1) ;=> (1) (make-a-list3+ 1 2 3 4 5) ;=> (1 2 3 (4 5))
The %& argument in make-a-list3+ is used to specify the variable arguments as discussed previously.
Programmers are typically accustomed to dealing with variables and mutation. Clojure’s closest analogy to the variable is the Var. A Var is named by a symbol and holds a single value. Its value can be changed while the program is running, but this is best reserved for the programmer making manual changes. A Var’s value can also be shadowed by a thread local value, though this doesn’t change its original value or root binding.
Using def is the most common way to create Vars in Clojure:
(def x 42)
Using def to associate the value 42 to the symbol x creates what’s known as a root binding—a binding that’s the same across all threads, unless otherwise rebound relative to specific threads. By default, all threads start with the root binding, which is their associated value in the absence of a thread-bound value.
The trivial case is that the symbol x is bound to the value 42. Because we used def to create the Var’s root binding, we should observe that even other threads will view the same root binding by default:
(.start (Thread. #(println "Answer: " x))) ; Answer: 42
Vars don’t require a value; instead we can simply declare them and defer the responsibility of binding their values to individual threads:[6]
6 We’ll talk more about per-thread bindings in chapter 11.
(def y) y ;=> java.lang.IllegalStateException: Var user/y is unbound.
Functions and vars theoretically provide all you need to implement any algorithm, and some languages leave you with exactly these “atomic” constructs.
Clojure’s function and value binding capabilities provide a basis for much of what a developer needs to start getting operational code, but a large part of the story is missing. Clojure also provides capabilities for creating local value bindings, looping constructs, and aggregating blocks of functionality.
Use the do form when you have a series or block of expressions that need to be treated as one. All the expressions will be evaluated, but only the last one will be returned:
(do 6 (+ 5 4) 3) ;=> 3
The expressions 6 and (+ 5 4) are perfectly valid and legal. The addition in (+ 5 4) is even done, but the value is thrown away—only the final expression 3 is returned. The middle bits of the do form are typically where the side-effects occur.
Clojure doesn’t have local variables, but it does have locals; they just can’t vary. Locals are created and their scope defined using a let form, which starts with a vector that defines the bindings, followed by any number of expressions that make up the body. The vector starts with a binding form (usually just a symbol), which is the name of a new local. This is followed by an expression whose value will be bound to this new local for the remainder of the let form. You can continue pairing binding names and expressions to create as many locals as you need. All of them will be available in the body of the let:
(let [r 5
pi 3.1415
r-squared (* r r)]
(println "radius is" r)
(* pi r-squared))
The body is sometimes described as an “implicit do” because it follows the same rules: you may include any number of expressions and all will be evaluated, but only the value of the last one is returned.
All of the binding forms in the previous example are simple symbols: r, pi, and r-squared. More complex binding expressions can be used to pull apart expressions that return collections. This feature is called destructuring: see section 2.9 for details.
Because they’re immutable, locals can’t be used to accumulate results; instead, you’d use a high level function or loop/recur form.
The classic way to build a loop in a Lisp is a recursive call, and it’s in Clojure as well. Using recursion sometimes requires thinking about your problem in a different way than imperative languages encourage; but recursion from a tail position is in many ways like a structured goto, and has more in common with an imperative loop than it does with other kinds of recursion.
Clojure has a special form called recur that’s specifically for tail recursion:
(defn print-down-from [x]
(when (pos? x)
(println x)
(recur (dec x))))
This is nearly identical to how you’d structure a while loop in an imperative language. One significant difference is that the value of x isn’t decremented somewhere in the body of the loop. Instead, a new value is calculated as a parameter to recur, which immediately does two things: rebinds x to the new value and returns control to the top of print-down-from.
If the function has multiple arguments, the recur call must as well, just as if you were calling the function by name instead of using the recur special form. And just as with a function call, the expressions in the recur are evaluated in order first and only then bound to the function arguments simultaneously.
The previous example doesn’t concern itself with return values; it’s just about the println side effects. Here’s a similar loop that builds up an accumulator and returns the final result:
(defn sum-down-from [sum x]
(if (pos? x)
(recur (+ sum x) (dec x))
sum))
The only ways out of the function are recur, which isn’t really a way out, and sum. So when x is no longer positive, the function will return the value of sum:
(sum-down-from 0 10) ;=> 55
You may have noticed that the two preceding functions used different blocks: the first when and the second if. You’ll often see one or the other used as a conditional, but it’s not always immediately apparent why. In general, the reasons to use when are
The reasons for the use of if would therefore be the inverse of those listed.
Sometimes you want to loop back not to the top of the function, but to somewhere inside. For example, in sum-down-from you might prefer that callers not have to provide an initial value for sum. To help, there’s a loop form that acts exactly like let but provides a target for recur to jump to. It’s used like this:
(defn sum-down-from [initial-x]
(loop [sum 0, x initial-x]
(if (pos? x)
(recur (+ sum x) (dec x))
sum)))
Upon entering the loop form, the locals sum and x are initialized, just as they would be for a let.
A recur always loops back to the closest enclosing loop or fn, so in this case it’ll go to the loop. The loop locals are rebound to the values given in recur. The looping and rebinding will continue until finally x is no longer positive. The return value of the whole loop expression is sum, just as it was for the earlier function.
Now that we’ve looked at a couple examples of how to use recur, we must discuss an important restriction. The recur form can only appear in the tail position of a function or loop. So what’s a tail position? Succinctly, a form is in the tail position of an expression when its value may be the return value of the whole expression. Consider this function:
(defn absolute-value [x]
(if (pos? x)
x ; "then" clause
(- x))) ; "else" clause
It takes a single parameter and names it x. If x is already a positive number, then x is returned; otherwise the opposite of x is returned.
The if form is in the function’s tail position because whatever it returns, the whole function will return. The x in the “then” clause is also in a tail position of the function. But the x in the “else” clause is not in the function’s tail position because the value of x is passed to the - function, not returned directly. The else clause as a whole (- x) is in a tail position.
If you try to use the recur form somewhere other than a tail position, Clojure will remind you at compile time:
(fn [x] (recur x) (println x)) ; java.lang.UnsupportedOperationException: ; Can only recur from tail position
You’ve seen how Clojure provides core functionality available to most popular programming languages, albeit from a different bent. But in the next section, we’ll cover the notion of quoting forms, which are in many ways unique to the Lisp family of languages and may seem alien to programmers coming from classically imperative and/ or object-oriented languages.
Clojure has two quoting forms: quote and syntax-quote. Both are simple bits of syntax you can put in front of a form in your program. They’re the primary ways for including literal scalars and composites in your Clojure program without evaluating them as code. But before quoting forms can make sense, you need a solid understanding of how expressions are evaluated.
When a collection is evaluated, each of its contained items is evaluated first:[7]
7 ...unless it’s a list that starts with the name of a macro or special form. We’ll get to that later.
(cons 1 [2 3])
If you enter this at the REPL, the form as a whole will be evaluated. In this specific example, the function cons “constructs” a new sequence with its first argument in the front of the sequence provided as its second. Because the form is a list, each of the items will be evaluated first. A symbol, when evaluated, is resolved to a local, a Var, or a Java class name. If a local or a Var, its value will be returned:
cons ;=> #<core$cons__3806 clojure.core$cons__3806@24442c76>
Literal scalar values evaluate to themselves—evaluating one just returns the same thing:
1 ;=> 1
The evaluation of another kind of collection, a vector, starts again by evaluating the items it contains. Because they’re literal scalars, nothing much happens. Once that’s done, evaluation of the vector can proceed. Vectors, like scalars and maps, evaluate to themselves:
[2 3] ;=> [2 3]
Now that all the items of the original list have been evaluated (to a function, the number 1, and the vector [2 3]), evaluation of the whole list can proceed. Lists are evaluated differently from vectors and maps: they call functions, or trigger special forms, as shown:
(cons 1 [2 3]) ;=> (1 2 3)
Whatever function was at the head of the list, cons in this case, is called with the remaining items of the list as arguments.
Using a special form looks like calling a function—a symbol as the first item of a list:
(quote tena)
Each special form has its own evaluation rules. The quote special form simply prevents its argument from being evaluated at all. Though the symbol tena by itself might evaluate to the value of a Var with the value 9, when it’s inside a quote form, it won’t:
(def tena 9) (quote tena) ;=> tena
Instead, the whole form evaluates to just the symbol itself. This works for arbitrarily complex arguments to quote: nested vectors, maps, even lists that would otherwise be function calls, macro calls, or even more special forms. The whole thing is returned:
(quote (cons 1 [2 3])) ;=> (cons 1 [2 3])
There are a few reasons you might use the quote form, but by far the most common is so that you can use a literal list as a data collection without having Clojure try to call a function. We’ve been careful to use vectors in the examples so far in this section because vectors are never themselves function calls. But if we wanted to use a list instead, a naive attempt would fail:
(cons 1 (2 3)) ; java.lang.ClassCastException: ; java.lang.Integer cannot be cast to clojure.lang.IFn
That’s Clojure telling us that an integer (the number 2 here) can’t be used as a function. So we have to prevent the form (2 3) from being treated like a function call—exactly what quote is for:
(cons 1 (quote (2 3))) ;=> (1 2 3)
In other Lisps, this need is so common that they provide a shortcut: a single quote. Although it’s used less in Clojure, it’s still provided. The previous example can also be written as
(cons 1 '(2 3)) ;=> (1 2 3)
And look at that: one less pair of parens—always welcome in a Lisp. Remember though that quote affects all of its argument, not just the top level. So even though it worked in the preceding examples to replace [] with '(), this may not always give you the results you want:
[1 (+ 2 3)] ;=> [1 5] '(1 (+ 2 3)) ;=> (1 (+ 2 3))
Finally, note that the empty list () already evaluates to itself; it doesn’t need to be quoted. Quoting the empty list isn’t idiomatic Clojure.
Like the quote, syntax-quote prevents its argument and subforms from being evaluated. Unlike quote, it has a few extra features that make it ideal for constructing collections to be used as code.
Syntax-quote is written as a single back-quote:
`(1 2 3) ;=> (1 2 3)
It doesn’t expand to a simple form like quote, but to whatever set of expressions is required to support the following features.[8]
8 A future version of Clojure is likely to expand the back-quote to syntax-quote at read time and implement the rest of syntax-quote’s features as a macro or special form.
A symbol can begin with a namespace and a slash. These can be called qualified symbols:
clojure.core/map clojure.set/union i.just.made.this.up/quux
Syntax-quote will automatically qualify all unqualified symbols in its argument:
`map ;=> clojure.core/map `Integer ;=> java.lang.Integer `(map even? [1 2 3]) ;=> (clojure.core/map clojure.core/even? [1 2 3])
If the symbol doesn’t name a Var or class that exists yet, syntax-quote will use the current namespace:
`is-always-right ;=> user/is-always-right
This behavior will come in handy in chapter 8, when we discuss macros.
As you discovered, the quote special form prevents its argument, and all of its sub-forms, from being evaluated. But there will come a time when you’ll want some of its constituent forms to be evaluated. The way to accomplish this feat is to use what’s known as an unquote. An unquote is used to demarcate specific forms as requiring evaluation by prefixing them with the symbol ~ within the body of a syntax-quote:
`(+ 10 (* 3 2)) ;=> (clojure.core/+ 10 (clojure.core/* 3 2)) `(+ 10 ~(* 3 2)) ;=> (clojure.core/+ 10 6)
What just happened? The final form uses an unquote to evaluate the subform (* 3 2), which of course performs a multiplication of 3 and 2, thus inserting the result into the outermost syntax-quoted form. The unquote can be used to denote any Clojure expression as requiring evaluation:
`(1 2 ~3) ;=> (1 2 3) (let [x 2] `(1 ~x 3)) ;=> (1 2 3) `(1 ~(2 3)) ;=> java.lang.ClassCastException: java.lang.Integer
Whoops! By using the unquote, we’ve told Clojure that the marked form should be evaluated. But the marked form here is (2 3), and what happens when Clojure encounters an expression like this? It attempts to evaluate it as a function! Therefore, care needs to be taken with unquote to ensure that the form requiring evaluation is of the form that you expect. The more appropriate way to perform the previous task would thus be
(let [x '(2 3)] `(1 ~x)) ;=> (1 (2 3))
This provides a level of indirection such that the expression being evaluated is no longer (2 3) but x. But this new way breaks the pattern of the previous examples that returned a list of (1 2 3).
Clojure provides a handy feature to solve exactly the problem posed earlier. A variant of unquote called unquote-splicing works similarly to unquote, but a little differently:
(let [x '(2 3)] `(1 ~@x)) ;=> (1 2 3)
Note the @ in ~@, which tells Clojure to unpack the sequence x, splicing it into the resulting list rather than inserting it as a nested list.
Sometimes you need an unqualified symbol, such as for a parameter or let local name. The easiest way to do this inside a syntax-quote is to append a # to the symbol name. This will cause Clojure to generate a new unqualified symbol:
`potion# ;=> potion__211__auto__
Sometimes even this isn’t enough, either because you need to refer to the same symbol in multiple syntax-quotes or because you want to capture a particular unqualified symbol.
Until this point, we’ve covered many of the basic features making Clojure a unique flavor of Lisp. But one of the main goals that Clojure excels at meeting is that of interoperability with a host language and runtime, namely Java and the Java Virtual Machine.
Clojure is symbiotic with its host,[9] providing its rich and powerful features, while Java provides an object model, libraries, and runtime support. In this section, we’ll take a brief look at how Clojure allows you to access Java classes and class members, and how you can create instances and access their members.
9 We’ll focus on the Java Virtual Machine throughout this book, but Clojure has also been hosted on the .NET Common Language Runtime (CLR) and JavaScript (http://clojurescript.n01se.net/repl/).
Clojure provides powerful mechanisms for accessing, creating, and mutating Java classes and instances. The trivial case is accessing static class properties:
java.util.Locale/JAPAN ;=> #<Locale ja_JP>
Idiomatic Clojure prefers that you access static class members using a syntax like accessing a namespace-qualified Var:
(Math/sqrt 9) ;=> 3.0
The preceding call is to the java.lang.Math#sqrt static method.
Creating Java class instances is likewise a trivial matter with Clojure. The new special form closely mirrors the Java model:
(new java.util.HashMap {"foo" 42 "bar" 9 "baz" "quux"})
;=> #<HashMap {baz=quux, foo=42, bar=9}>
The second, more succinct, Clojure form to create instances is actually the idiomatic form:
(java.util.HashMap. {"foo" 42 "bar" 9 "baz" "quux"})
;=> #<HashMap {baz=quux, foo=42, bar=9}>
As you can see, the class name was followed by a dot in order to signify a constructor call.
To access instance properties, precede the property or method name with a dot:
(.x (java.awt.Point. 10 20)) ;=> 10
This returns the value of the field x from the Point instance given.
To access instance methods, the dot form allows an additional argument to be passed to the method:
(.divide (java.math.BigDecimal. "42") 2M) ;=> 21M
The preceding example calls the #divide method on the class BigDecimal.
In the absence of mutators in the form setXXX, Java instance properties can be set via the set! function:
(let [origin (java.awt.Point. 0 0)] (set! (.x origin) 15) (str origin)) ;=> "java.awt.Point[x=15,y=0]"
The first argument to set! is the instance member access form.
When working with Java, it’s common practice to chain together a sequence of method calls on the return type of the previous method call:
new java.util.Date().toString().endsWith("2010") /* Java code */
Using Clojure’s dot special form, the following code is equivalent:
(.endsWith (.toString (java.util.Date.)) "2010") ; Clojure code ;=> true
Though correct, the preceding code is difficult to read and will only become more so when we lengthen the chain of method calls. To combat this, Clojure provides the .. macro, which can simplify the call chain as follows:
(.. (java.util.Date.) toString (endsWith "2010"))
The preceding .. call closely follows the equivalent Java code and is much easier to read. Bear in mind, you might not see .. used often in Clojure code found in the wild outside of the context of macro definitions. Instead, Clojure provides the -> and ->> macros, which can be used similarly to the .. macro but are also useful in non-interop situations, thus making them the preferred method call facilities in most cases. The -> and ->> macros are covered in more depth in the introduction to chapter 8.
When working with Java, it’s also common to initialize a fresh instance by calling a set of mutators:
java.util.HashMap props = new java.util.HashMap(); /* More java code. */
props.put("HOME", "/home/me"); /* Sorry. */
props.put("SRC", "src");
props.put("BIN", "classes");
But using this method is overly verbose and can be streamlined using the doto macro, which takes the form
(doto (java.util.HashMap.)
(.put "HOME" "/home/me")
(.put "SRC" "src")
(.put "BIN" "classes"))
;=> #<HashMap {HOME=/home/me, BIN=classes, SRC=src}>
Though these Java and Clojure comparisons are useful, it shouldn’t be assumed that their compiled structures are the same.
Clojure provides the reify and deftype macros as possible ways to create realizations of Java interfaces, but we’ll defer covering them until chapter 9. Additionally, Clojure provides a macro named proxy that can be used to implement interfaces and extend base classes on the fly. Similarly, using the gen-class macro, you can generate statically named classes. More details about proxy and gen-class are available in chapter 10.
We’ll now talk briefly about Clojure’s facilities for handling exceptions. Like Java, Clojure provides a couple of forms for throwing and catching runtime exceptions: namely throw and catch, respectively.
The mechanism to throw an exception is fairly straightforward:
(throw (Exception. "I done throwed")) ;=> java.lang.Exception: I done throwed
The syntax for catching exceptions in Clojure is similar to that of Java:
(defn throw-catch [f]
[(try
(f)
(catch ArithmeticException e "No dividing by zero!")
(catch Exception e (str "You are so bad " (.getMessage e)))
(finally (println "returning... ")))])
(throw-catch #(/ 10 5))
; returning...
;=> [2]
(throw-catch #(/ 10 0))
; returning...
;=> ["No dividing by zero!"]
(throw-catch #(throw (Exception. "foo")))
; returning...
;=> ["You are so bad foo"]
The major difference between the way that Java handles exceptions compared to Clojure is that Clojure doesn’t adhere to checked exception requirements. In the next, final section of our introduction to Clojure, we present namespaces, which might look vaguely familiar if you’re familiar with Java or Common Lisp.
Clojure’s namespaces provide a way to bundle related functions, macros, and values. In this section, we’ll briefly talk about how to create namespaces and how to reference and use things from other namespaces.
To create a new namespace, you can use the ns macro:
(ns joy.ch2)
Whereupon your REPL prompt will now display as:
joy.ch2=>
This prompt shows that you’re working within the context of the joy.ch2 namespace. Clojure also provides a Var *ns* that holds the value of the current namespace. Any Var created will be a member of the current namespace:
(defn hello [] (println "Hello Cleveland!")) (defn report-ns [] (str "The current namespace is " *ns*)) (report-ns) ;=> "The current namespace is joy.ch2"
Entering a symbol within a namespace will cause Clojure to attempt to look up its value within the current namespace:
hello ;=> #<ch2$hello joy.ch2$hello@2af8f5>
You can create new namespaces at any time:
(ns joy.another)
Again, you’ll notice that your prompt has changed, indicating that the new context is joy.another. Attempting to run report-ns will no longer work:
(report-ns) ; java.lang.Exception: ; Unable to resolve symbol: report-ns in this context
This is because report-ns exists in the joy.ch1 namespace and is only accessible via its fully qualified name joy.ch2/report-ns. But this will only work for namespaces created locally or those previously loaded, which we’ll discuss next.
Creating a namespace is straightforward, but how do you load namespaces? Clojure provides a convenience directive :require to take care of this task. Observe the following:
(ns joy.req
(:require clojure.set))
(clojure.set/intersection #{1 2 3} #{3 4 5})
;=> #{3}
Using :require indicates that you want the clojure.set namespace loaded, but you don’t want the mappings of symbols to functions in the joy.req namespace. You can also use the :as directive to create an additional alias to clojure.set:
(ns joy.req-alias
(:require [clojure.set :as s]))
(s/intersection #{1 2 3} #{3 4 5})
;=> #{3}
The qualified namespace form looks the same as a call to a static class method. The difference is that a namespace symbol can only be used as a qualifier, whereas a class symbol can also be referenced independently:
clojure.set ; java.lang.ClassNotFoundException: clojure.set java.lang.Object ;=> java.lang.Object
The vagaries of namespace mappings from symbols to Vars both qualified and unqualified have the potential for confusion between class names and static methods in the beginning, but the differences will begin to feel natural as you progress. In addition, idiomatic Clojure code will tend to use my.Class and my.ns for naming classes and namespaces respectively, to help eliminate potential confusion.
Sometimes you’ll want to create mappings from Vars in another namespace to names in your own, in order to avoid calling each function or macro with the qualifying namespace symbol. To create these unqualified mappings, Clojure provides the :use directive:
(ns joy.use-ex
(:use [clojure.string :only [capitalize]]))
(map capitalize ["kilgore" "trout"])
;=> ("Kilgore" "Trout")
The :use directive indicates that only the function capitalize should be mapped in the namespace joy.use-ex. Specifying the Vars that you’d like explicit mappings for is good practice in Clojure, as it avoids creating many unnecessary names within a namespace. Unnecessary names increase the odds of names clashes, which you’ll see next. A similar directive to :use for managing precise mappings is :exclude
(ns joy.exclusion (:use [clojure.string :exclude [capitalize]])) ; WARNING: replace already refers to: #'clojure.core/replace in namespace: ; joy.exclusion, being replaced by: #'clojure.string/replace ; WARNING: reverse already refers to: #'clojure.core/reverse in namespace: ; joy.exclusion, being replaced by: #'clojure.string/reverse (map capitalize ["kilgore" "trout"]) ; java.lang.Exception: Unable to resolve symbol: capitalize in this context
The :exclude directive indicates that we wanted to map names for all of clojure. string’s Vars except for capitalize. Indeed, any attempt to use capitalize directly throws an exception. But it’s still accessible via clojure.string/capitalize. The reason for this accessibility is because :use implicitly performs a :require directive in addition to creating mappings. As you might’ve noticed, the creation of the joy. exclusion namespace signaled two warnings. The reason was that the clojure. string namespace defines two functions reverse and replace that are already defined in the clojure.core namespace—which was already loaded by using ns. Therefore, when either of those functions are used, the last Var definition wins:
(reverse "abc") ;=> "cba" (clojure.core/reverse "abc") (\c \b \a)
The clojure.string version of reverse takes precedence over the clojure.core version, which may or may not be what we wanted. You should always strive to eliminate the warnings that Clojure presents in these cases. The most obvious strategy for resolving these particular warnings would be to use the :require directive to create a namespace alias with :as as we showed in the previous section.
Clojure also provides a :refer directive that works almost exactly like :use except that it only creates mappings for libraries that have already been loaded:
(ns joy.yet-another (:refer joy.ch1)) (report-ns) ;=> "The current namespace is #<Namespace joy.yet-another>"
The use of :refer in this way creates a mapping from the name report-ns to the actual function located in the namespace joy.ch2 so that the function can be called normally. You could also set an alias for the same function using the :rename keyword taking a map, as shown:
(ns joy.yet-another
(:refer joy.ch1 :rename {hello hi}))
(hi)
; Hello Cleveland!
Any namespaces referenced must already be loaded implicitly by being previously defined or by being one of Clojure’s core namespaces, or explicitly loaded through the use of :require. It should be noted that :rename also works with the :use directive.
To use unqualified Java classes within any given namespace, they should be imported via the :import directive, as shown:
(ns joy.java
(:import [java.util HashMap]
[java.util.concurrent.atomic AtomicLong]))
(HashMap. {"happy?" true})
;=> #<HashMap {happy?=true}>
(AtomicLong. 42)
;=> 42
As a reminder, any classes in the Java java.lang package are automatically imported when namespaces are created. We’ll discuss namespaces in more detail in sections 9.1 and 10.2.
We named this chapter “Drinking from the Clojure firehose”—and you’ve made it through! How does it feel? We’ve only provided an overview of the topics needed to move on to the following chapters instead of a full-featured language tutorial. Don’t worry if you don’t fully grasp the entirety of Clojure the programming language; understanding will come as you work your way through the book.
In the next chapter, we’ll take a step back and delve into some topics that can’t be easily categorized, but that deserve attention because of their ubiquity. It’ll be short and sweet and give you a chance to take a breath before moving into the deeper discussions on Clojure later in the book.