Special Forms

(def symbol init?)

Creates and interns or locates a global var with the name of symbol and a namespace of the value of the current namespace (*ns*). If init is supplied, it is evaluated, and the root binding of the var is set to the resulting value. If init is not supplied, the root binding of the var is unaffected. def always applies to the root binding, even if the var is thread-bound at the point where def is called. def yields the var itself (not its value). Throws an exception if symbol is already in the namespace and not mapped to an interned var.


Any metadata on the symbol will be evaluated, and become metadata on the var itself. There are several metadata keys that have special interpretation:


:private 

a boolean indicating the access control for the var. If this key is not present, the default access is public (e.g. as if :private false).


:doc 

a string containing short (1-3 line) documentation for the var contents


:test 

a fn of no args that uses assert to check various operations. The var itself will be accessible during evaluation of a literal fn in the metadata map.


:tag 

a symbol naming a class or a Class object that indicates the Java type of the object in the var, or its return value if the object is a fn.


In addition the compiler will place the following keys on the var:


:file string

:line int

:name simple symbol

:ns namespace in which var is interned

:macro true if var names a macro

:arglists a list of vector(s) of argument forms, as were supplied to defn


The var metadata can be used for application-specific purposes as well. Consider using namespace-qualified keys (e.g. :myns/foo) to avoid clashes.


(defn
#^{:doc "mymax [xs+] gets the maximum value in xs using > "
   :test (fn []
             (assert (= 42  (max 2 42 5 4))))
   :user/comment "this is the best fn ever!"}
  mymax
  ([x] x)
  ([x y] (if (> x y) x y))
  ([x y & more]
   (reduce mymax (mymax x y) more)))
user=> ^#'mymax
->{:name mymax,
 :user/comment "this is the best fn ever!",
 :doc "mymax [xs+] gets the maximum value in xs using >",
 :file "REPL",
 :ns #,
 :test user.fn__7290@2c3438,
 :line 126}


Many macros expand into def (e.g. defn, defmacro), and thus also convey metadata for the resulting var from the symbol used as the name.


Using def to modify the root value of a var at other than the top level is usually an indication that you are using the var as a mutable global, and is considered bad style. Consider either using binding to provide a thread-local value for the var, or putting a ref or agent in the var and using transactions or actions for mutation.


(if test then else?)

Evaluates test. If not nil or false, evaluates and yields then, otherwise, evaluates and yields else. If else is not supplied it defaults to nil. All of the other conditionals in Clojure are based upon the same logic, that is, nil and false constitute logical falsity, and everything else constitutes logical truth, and those meaning apply throughout.


(do exprs*)

Evaluates the expressions in order and returns the value of the last. If no expressions are supplied, returns nil.


(let [bindings* ] exprs*)

binding => binding-form init-expr


Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. The bindings are sequential, so each binding can see the prior bindings. The exprs are contained in an implicit do. If a binding symbol is annotated with a metadata tag, the compiler will try to resolve the tag to a class name and presume that type in subsequent references to the binding. The simplest binding-form is a symbol, which is bound to the entire init-expr:

(let [x 1
      y x]
  y)
-> 1

Clojure supports abstract structural binding, often called destructuring, in let binding lists, fn parameter lists, and any macro that expands into a let or fn. The basic idea is that a binding-form can be a data structure literal containing symbols that get bound to the respective parts of the init-expr. The binding is abstract in that a vector literal can bind to anything that is sequential, while a map literal can bind to anything that is associative.

Vector binding-exprs allow you to bind names to parts of sequential things (not just vectors), like vectors, lists, seqs, strings, arrays, and anything that supports seq or nth. The basic sequential form is a vector of binding-forms, which will be bound to successive elements from the init-expr, looked up via nth. In addition, and optionally, & followed by a binding-forms will cause that binding-form to be bound to the 'rest' of the sequence, i.e. that part not yet bound, looked up via nthrest. Finally, also optional, :as followed by a symbol will cause that symbol to be bound to the entire init-expr:

(let [[a b c & d :as e] [1 2 3 4 5 6 7]] 
  [a b c d e])
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]

These forms can be nested:

(let [[[x1 y1][x2 y2]] [[1 2] [3 4]]]
   [x1 y1 x2 y2])
->[1 2 3 4]

Strings work too:

(let [[a b & c :as str] "asdjhhfdas"]
   [a b c str])
->[\a \s (\d \j \h \h \f \d \a \s) "asdjhhfdas"]

Map binding-forms allow you to bind names to parts of associative things (not just maps), like maps, vectors, string and arrays (the latter three have integer keys). It consists of a map of binding-form-key pairs, each symbol being bound to the value in the init-expr at the key. In addition, and optionally, an :as key in the binding form followed by a symbol will cause that symbol to be bound to the entire init-expr. Also optionally, an :or key in the binding form followed by another map may be used to supply default values for some or all of the keys if they are not found in the init-expr:

(let [{a :a, b :b, c :c, :as m :or {a 2 b 3}} {:a 5 :c 6}]
    [a b c m])
->[5 3 6 {:c 6, :a 5}]

Since binding forms can be nested within one another arbitrarily, you can pull apart just about anything:

(let [{j :j, k :k, i :i, [r s & t :as v] :ivec, :or {i 12 j 13}}
	 {:j 15 :k 16 :ivec [22 23 24 25]}]
  [i j k r s t v])
-> [12 15 16 22 23 (24 25) [22 23 24 25]]

Locals created with let are not variables. Once created their values never change!  


(quote form)

Yields the unevaluated form.

user=> '(a b c)
(a b c)

Note there is no attempt made to call the function a. The return value is a list of 3 symbols.


(var symbol)

The symbol must resolve to a var, and the Var object itself (not its value) is returned. The reader macro #'x expands to (var x).


(fn name? [params* ] exprs*)

(fn name? ([params* ] exprs*)+)

params => positional-params* , or positional-params* & rest-param

positional-param => binding-form

rest-param => binding-form

name => symbol


Defines a function (fn). Fns are first-class objects that implement the IFn interface. The IFn interface defines an invoke() function that is overloaded with arity ranging from 0-20. A single fn object can implement one or more invoke methods, and thus be overloaded on arity. One and only one overload can itself be variadic, by specifying the ampersand followed by a single rest-param. Such a variadic entry point, when called with arguments that exceed the positional params, will find them in a seq contained in the rest param. If the supplied args do not exceed the positional params, the rest param will be nil.


The first form defines a fn with a single invoke method. The second defines a fn with one or more overloaded invoke methods. The arities of the overloads must be distinct. In either case, the result of the expression is a single fn object.


The exprs are compiled in an environment in which the params are bound to the actual arguments. The exprs are enclosed in an implicit do. If a name symbol is provided, it is bound within the function definition to the function object itself, allowing for self-calling, even in anonymous functions. If a param symbol is annotated with a metadata tag, the compiler will try to resolve the tag to a class name and presume that type in subsequent references to the binding.

(def mult
  (fn this
      ([] 1)
      ([x] x)
      ([x y] (. clojure.lang.Num (multiply x y)))
      ([x y & more]
          (apply this (this x y) more))))


Note that named fns such as mult are normally defined with defn, which expands into something such as the above. 


A fn (overload) defines a recursion point at the top of the function, with arity equal to the number of params including the rest param, if present. See recur.


IFns implement the Java Callable, Runnable and Comparator interfaces.


(loop [bindings* ] exprs*)

loop is exactly like let, except that it establishes a recursion point at the top of the loop, with arity equal to the number of bindings. See recur.


(recur exprs*)

Evaluates the exprs in order, then, in parallel, rebinds the bindings of the recursion point to the values of the exprs. If the recursion point was a fn method, then it rebinds the params. If the recursion point was a loop, then it rebinds the loop bindings. Execution then jumps back to the recursion point. The recur expression must match the arity of the recursion point exactly. In particular, if the recursion point was the top of a variadic fn method, there is no gathering of rest args - a single seq (or null) should be passed. recur in other than a tail position is an error.


Note that recur is the only non-stack-consuming looping construct in Clojure. There is no tail-call optimization and the use of self-calls for looping of unknown bounds is discouraged. recur is functional and its use in tail-position is verified by the compiler.

(def factorial
  (fn [n]
    (loop [cnt n acc 1]
       (if (zero? cnt)
            acc
          (recur (dec cnt) (* acc cnt))))))


(throw expr)

The expr is evaluated and thrown, therefor it should yield an instance of some derivee of Throwable.


(try expr* catch-clause* finally-clause?)

catch-clause -> (catch classname name expr*)

finally-clause -> (finally expr*)


The exprs are evaluated and, if no exceptions occur, the value of the last is returned. If an exception occurs and catch clauses are provided, each is examined in turn and the first for which the thrown exception is an instance of the named class is considered a matching catch clause. If there is a matching catch clause, its exprs are evaluated in a context in which name is bound to the thrown exception, and the value of the last is the return value of the function. If there is no matching catch clause, the exception propagates out of the function. Before returning, normally or abnormally, any finally exprs will be evaluated for their side effects.


(monitor-enter x)

(monitor-exit x)

These are synchronization primitives that should be avoided in user code. Use the locking macro.



Other Special Forms

The  special forms dot  ('.'), new, instance? and set! of fields are described in the Java Interop section of the reference.


set! of vars is described in the Vars section of the reference.

Copyright © Rich Hickey