( …​ ) - List

Lists are sequential heterogeneous collections implemented as a linked list.

A list of three values:

(1 "two" 3.0)

[ …​ ] - Vector

Vectors are sequential, indexed, heterogeneous collections. Indexing is 0-based.

An example of retrieving the value at index 1 in a vector of three values:

user=> (get ["a" 13.7 :foo] 1)
13.7

{ …​ } - Map

Maps are heterogeneous collections specified with alternating keys and values:

user=> (keys {:a 1 :b 2})
(:a :b)

# - Dispatch character

You’ll see this character beside another e.g. #( or #".

# is a special character that tells the Clojure reader (the component that takes Clojure source and "reads" it as Clojure data) how to interpret the next character using a read table. Although some Lisps allow the read table to be extended by users, Clojure does not.

The # is also used at the end of a symbol when creating generated symbols inside a syntax quote.

#{ …​ } - Set

See # for additional details.

#{…​} defines a set (a collection of unique values), specifically a hash-set. The following are equivalent:

user=> #{1 2 3 4}
#{1 2 3 4}
user=> (hash-set 1 2 3 4)
#{1 2 3 4}

Sets cannot contain duplicates and thus the set reader will throw an exception in this case as it is an invalid literal. When items are added to a set, they are simply dropped if the value is already present.

user=> #{1 2 3 4 1}
Syntax error reading source at (REPL:83:13).
Duplicate key: 1

#_ - Discard

See # for additional details.

#_ tells the reader to ignore the next form completely.

user=> [1 2 3 #_ 4 5]
[1 2 3 5]

Note that the space following #_ is optional, so

user=> [1 2 3 #_4 5]
[1 2 3 5]

also works. Also note that the discard character works in edn.

A neat trick is that multiple #_ can be stacked to omit multiple forms

user=> {:a 1, #_#_ :b 2, :c 3}
{:a 1, :c 3}

The docs suggest that "The form following #_ is completely skipped by the reader (This is a more complete removal than the comment macro which yields nil).". This can prove useful for debugging situations or for multiline comments.

#"…​" - Regular Expression

See # for additional details.

#" indicates the start of a regular expression

user=> (re-matches #"^test$" "test")
"test"

This form is compiled at read time into a host-specific regex machinery, but it is not available in edn. Note that when using regexes in Clojure, Java string escaping is not required

#(…​) - Anonymous function

See # for additional details.

#( begins the short hand syntax for an inline function definition. The following two snippets of code are similar:

; anonymous function taking a single argument and printing it
(fn [line] (println line))

; anonymous function taking a single argument and printing it - shorthand
#(println %)

The reader expands an anonymous function into a function definition whose arity (the number of arguments it takes) is defined by how the % placeholders are declared. See the % character for discussion around arity.

user=> (macroexpand `#(println %))
(fn* [arg] (clojure.core/println arg)) ; argument names shortened for clarity

#' - Var quote

#' is the var quote which expands into a call to the var function:

user=> (read-string "#'foo")
(var foo)
user=> (def nine 9)
#'user/nine
user=> nine
9
user=> (var nine)
#'user/nine
user=> #'nine
#'user/nine

When used it will attempt to return the referenced var. This is useful when you want to talk about the reference/declaration instead of the value it represents. See the use of meta in the metadata (^) discussion.

Note that var quote is not available in edn.

## - Symbolic values

Clojure can read and print the symbolic values ##Inf, ##-Inf, and ##NaN. These are also available in edn.

user=> (/ 1.0 0.0)
##Inf
user=> (/ -1.0 0.0)
##-Inf
user=> (Math/sqrt -1.0)
##NaN

#inst, #uuid, and #js etc. - tagged literals

Tagged literals are defined in edn and supported by the Clojure and ClojureScript readers natively. The #inst and #uuid tags are defined by edn, whereas the #js tag is defined by ClojureScript.

We can use Clojure’s read-string to read a tagged literal (or use it directly):

user=> (type #inst "2014-05-19T19:12:37.925-00:00")
java.util.Date ;; this is host dependent
(read-string "#inst \"2014-05-19T19:12:37.925-00:00\"")
#inst "2014-05-19T19:12:37.925-00:00"

A tagged literal tells the reader how to parse the literal value. Other common uses include #uuid for expressing UUIDs and in the ClojureScript world an extremely common use of tagged literals is #js which can be used to convert ClojureScript data structures into JavaScript structures directly. Note that #js doesn’t convert recursively, so if you have a nested data-structure, use js->clj.

Note that while #inst and #uuid are available in edn, #js is not.

%, %n, %& - Anonymous function arguments

% is an argument in an anonymous function (…​) as in (* % %).

When an anonymous function is expanded, it becomes an fn form and % args are replaced with gensym’ed names (here we use arg1, etc for readability):

user=> (macroexpand `#(println %))
(fn* [arg1] (clojure.core/println arg1))

Numbers can be placed directly after the % to indicate the argument positions (1-based). Anonymous function arity is determined based on the highest number % argument.

user=> (macroexpand `#(println %1 %2))
(fn* [arg1 arg2] (clojure.core/println arg1 arg2)) ; takes 2 args

user=> (macroexpand `#(println %4))
(fn* [arg1 arg2 arg3 arg4] (clojure.core/println arg4)) ; takes 4 args doesn't use 3

You don’t have to use the arguments, but you do need to declare them in the order you’d expect an external caller to pass them in.

% and %1 can be used interchangeably:

user=> (macroexpand `#(println % %1)) ; use both % and %1
(fn* [arg1] (clojure.core/println arg1 arg1)) ; still only takes 1 argument

There is also %& which is the symbol used in a variadic anonymous function to represent the "rest" of the arguments (after the highest named anonymous argument).

user=> (macroexpand '#(println %&))
(fn* [& rest__11#] (println rest__11#))

Anonymous functions and % are not part of edn.

@ - Deref

@ expands into a call to the deref function, so these two forms are the same:

user=> (def x (atom 1))
#'user/x
user=> @x
1
user=> (deref x)
1
user=>

@ is used to get the current value of a reference. The above example uses @ to get the current value of an atom, but @ can be applied to other things such as future s, delay s, promises s etc. to force computation and potentially block.

Note that @ is not available in edn.

^ (and #^) - Metadata

^ is the metadata marker. Metadata is a map of values (with shorthand option) that can be attached to various forms in Clojure. This provides extra information for these forms and can be used for documentation, compilation warnings, typehints, and other features.

user=> (def ^{:debug true} five 5) ; meta map with single boolean value
#'user/five

We can access the metadata by the meta function which should be executed against the declaration itself (rather than the returned value):

user=> (def ^{:debug true} five 5)
#'user/five
user=> (meta #'five)
{:ns #<Namespace user>, :name five, :column 1, :debug true, :line 1, :file "NO_SOURCE_PATH"}

As we have a single value here, we can use a shorthand notation for declaring the metadata ^:name which is useful for flags, as the value will be set to true.

user=> (def ^:debug five 5)
#'user/five
user=> (meta #'five)
{:ns #<Namespace user>, :name five, :column 1, :debug true, :line 1, :file "NO_SOURCE_PATH"}

Another use of ^ is for type hints. These are used to tell the compiler what type the value will be and allow it to perform type specific optimizations thus potentially making resultant code faster:

user=> (def ^Integer five 5)
#'user/five
user=> (meta #'five)
{:ns #<Namespace user>, :name five, :column 1, :line 1, :file "NO_SOURCE_PATH", :tag java.lang.Integer}

We can see in that example the :tag property is set.

You can also stack the shorthand notations:

user=> (def ^Integer ^:debug ^:private five 5)
#'user/five
user=> (meta #'five)
{:ns #<Namespace user>, :name five, :column 1, :private true, :debug true, :line 1, :file "NO_SOURCE_PATH", :tag java.lang.Integer}

Originally, meta was declared with #^, which is now deprecated (but still works). Later, this was simplified to just ^ and that is what you will see in most Clojure, but occasionally you will encounter the #^ syntax in older code.

Note that metadata is available in edn, but type hints are not.

' - Quote

Quoting is used to indicate that the next form should be read but not evaluated. The reader expands ' into a call to the quote special form.

user=> (1 3 4) ; fails as it tries to invoke 1 as a function

Execution error (ClassCastException) at myproject.person-names/eval230 (REPL:1).
class java.lang.Long cannot be cast to class clojure.lang.IFn

user=> '(1 3 4) ; quote
(1 3 4)

user=> (quote (1 2 3)) ; using the longer quote method
(1 2 3)
user=>

; - Comment

; starts a line comment and ignores all input from its starting point to the end of the line.

user=> (def x "x") ; this is a comment
#'user/x
user=> ; this is a comment too
<returns nothing>

It is common in Clojure to use multiple semicolons for readability or emphasis, but these are all the same to Clojure

;; This is probably more important than

; this

: - Keyword

: is the indicator for a keyword. Keywords are often used as keys in maps and they provide faster comparisons and lower memory overhead than strings (because instances are cached and reused).

user=> (type :test)
clojure.lang.Keyword

Alternatively you can use the keyword function to create a keyword from a string

user=> (keyword "test")
:test

Keywords can also be invoked as functions to look themselves up as a key in a map:

user=> (def my-map {:one 1 :two 2})
#'user/my-map
user=> (:one my-map) ; get the value for :one by invoking it as function
1
user=> (:three my-map) ; it can safely check for missing keys
nil
user=> (:three my-map 3) ; it can return a default if specified
3
user => (get my-map :three 3) ; same as above, but using get
3

:: - Auto-resolved keyword

:: is used to auto-resolve a keyword in the current namespace. If no qualifier is specified, it will auto-resolve to the current namespace. If a qualifier is specified, it may use aliases in the current namespace:

user=> :my-keyword
:my-keyword
user=> ::my-keyword
:user/my-keyword
user=> (= ::my-keyword :my-keyword)
false

This is useful when creating macros. If you want to ensure that a macro that calls another function in the macro namespace correctly expands to call the function, you could use ::my-function to refer to the fully qualified name.

Note that :: is not available in edn.

#: and #:: - Namespace Map Syntax

Namespace map syntax was added in Clojure 1.9 and is used to specify a default namespace context when keys or symbols in a map where they share a common namespace.

The #:ns syntax specifies a fully-qualified namespace map prefix n alias in the namespace map prefix with, where ns is the name of a namespace and the prefix precedes the opening brace { of the map.

For example, the following map literal with namespace syntax:

#:person{:first "Han"
         :last "Solo"
         :ship #:ship{:name "Millennium Falcon"
                      :model "YT-1300f light freighter"}}

is read as:

{:person/first "Han"
 :person/last "Solo"
 :person/ship {:ship/name "Millennium Falcon"
               :ship/model "YT-1300f light freighter"}}

Note that these maps represent the identical object - these are just alternate syntaxes.

#:: can be used to auto-resolve the namespace of keyword or symbol keys in a map using the current namespace.

These two examples are equivalent:

user=> (keys {:user/a 1, :user/b 2})
(:user/a :user/b)
user=> (keys #::{:a 1, :b 2})
(:user/a :user/b)

Similar to autoresolved keywords, you can also use #::alias to auto-resolve with a namespace alias defined in the ns form:

(ns rebel.core
  (:require
    [rebel.person :as p]
    [rebel.ship   :as s] ))

#::p{:first "Han"
     :last "Solo"
     :ship #::s{:name "Millennium Falcon"
                :model "YT-1300f light freighter"}}

is read the same as:

{:rebel.person/first "Han"
 :rebel.person/last "Solo"
 :rebel.person/ship {:rebel.ship/name "Millennium Falcon"
                     :rebel.ship/model "YT-1300f light freighter"}}

/ - Namespace separator

/ can be the division function clojure.core//, but can also act as a separator in a symbol name to separate a symbol’s name and namespace qualifier, e.g. my-namespace/utils. Namespace qualifiers can thus prevent naming collisions for simple names.

\ - Character literal

\ indicates a literal character as in:

user=> (str \h \i)
"hi"

There are also a small number of special characters to name special ASCII characters: \newline, \space, \tab, \formfeed, \backspace, and \return.

The \ can also be followed by a Unicode literal of the form \uNNNN. For example, \u03A9 is the literal for Ω.

$ - Inner class reference

Used to reference inner classes and interfaces in Java. Separates the container class name and the inner class name.

(import (basex.core BaseXClient$EventNotifier)

(defn- build-notifier [notifier-action]
  (reify BaseXClient$EventNotifier
    (notify [this value]
      (notifier-action value))))

EventNotifier is an inner interface of the BaseXClient class which is an imported Java class

->, ->>, some->, cond->, as-> etc. - Threading macros

These are threading macros. Please refer to Official Clojure Documentation

` - Syntax quote

` is the syntax quote. Syntax quote is similar to quoting (to delay evaluation) but has some additional effects.

Basic syntax quote may look similar to normal quoting:

user=> (1 2 3)
Execution error (ClassCastException) at myproject.person-names/eval232 (REPL:1).
class java.lang.Long cannot be cast to class clojure.lang.IFn
user=> `(1 2 3)
(1 2 3)

However, symbols used within a syntax quote are fully resolved with respect to the current namespace:

user=> (def five 5)
#'user/five
user=> `five
user/five

Syntax quote is most used as a "template" mechanism within macros. We can write one now:

user=> (defmacro debug [body]
  #_=>   `(let [val# ~body]
  #_=>      (println "DEBUG: " val#)
  #_=>      val#))
#'user/debug
user=> (debug (+ 2 2))
DEBUG:  4
4

Macros are functions invoked by the compiler with code as data. They are expected to return code (as data) that can be further compiled and evaluated. This macro takes a single body expression and returns a let form that will evaluate the body, print its value, and then return the value. Here the syntax quote creates a list, but does not evaluate it. That list is actually code.

See ~@ and ~ for additional syntax allowed only within syntax quote.

~ - Unquote

See ` for additional information.

~ is unquote. That is within a syntax quoted ` form ~ will unquote the associated symbol, i.e. evaluate it in the current context:

user=> (def five 5) ; create a named var with the value 5
#'user/five
user=> five ; the symbol five is evaluated to its value
5
user=> `five ; syntax quoting five will avoid evaluating the symbol, and fully resolve it
user/five
user=> `~five ; within a syntax quoted block, ~ will turn evaluation back on just for the next form
5

Syntax quoting and unquote are essential tools for writing macros, which are functions invoked during compilation that take code and return code.

~@ - Unquote splicing

See ` and ~ for additional information.

~@ is unquote-splicing. Where unquote (~) evaluates a form and places the result into the quoted result, ~@ expects the evaluated value to be a collection and splices the contents of that collection into the quoted result.

user=> (def three-and-four (list 3 4))
#'user/three-and-four
user=> `(1 ~three-and-four) ; evaluates `three-and-four` and places it in the result
(1 (3 4))
user=> `(1 ~@three-and-four) ;  evaluates `three-and-four` and places its contents in the result
(1 3 4)

Again, this is a powerful tool for writing macros.

<symbol># - Gensym

A # at the end of a symbol is used to automatically generate a new symbol. This is useful inside macros to keep macro specifics from leaking into the userspace. A regular let will fail in a macro definition:

user=> (defmacro m [] `(let [x 1] x))
#'user/m
user=> (m)
Syntax error macroexpanding clojure.core/let at (REPL:1:1).
myproject.person-names/x - failed: simple-symbol? at: [:bindings :form :local-symbol]
  spec: :clojure.core.specs.alpha/local-name
myproject.person-names/x - failed: vector? at: [:bindings :form :seq-destructure]
  spec: :clojure.core.specs.alpha/seq-binding-form
myproject.person-names/x - failed: map? at: [:bindings :form :map-destructure]
  spec: :clojure.core.specs.alpha/map-bindings
myproject.person-names/x - failed: map? at: [:bindings :form :map-destructure]
  spec: :clojure.core.specs.alpha/map-special-binding

This is because symbols inside a syntax quote are fully resolved, including the local binding x here.

Instead you can append # to the end of the variable name and let Clojure generate a unique (unqualified) symbol:

user=> (defmacro m [] `(let [x# 1] x#))
#'user/m
user=> (m)
1
user=>

Importantly, every time a particular x# is used within a single syntax quote, the same generated name will be used.

If we expand this macro, we can see the gensym 'd name:

user=> (macroexpand '(m))
(let* [x__681__auto__ 1] x__681__auto__)

#? - Reader conditional

Reader conditionals are designed to allow different dialects of Clojure to share common code. The reader conditional behaves similarly to a traditional cond. The syntax for usage is #? and looks like this:

#?(:clj  (Clojure expression)
   :cljs (ClojureScript expression)
   :cljr (Clojure CLR expression)
   :default (fallthrough expression))

#?@ - Splicing Reader conditional

The syntax for a splicing reader conditional is #?@. It is used to splice lists into the containing form. So the Clojure reader would read this:

(defn build-list []
  (list #?@(:clj  [5 6 7 8]
            :cljs [1 2 3 4])))

as this:

(defn build-list []
  (list 5 6 7 8))

*var-name* - "Earmuffs"

Earmuffs (a pair of asterisk bookending var names) is a naming convention in many LISPs used to denote special vars. Most commonly in Clojure this is used to denote dynamic vars, i.e. ones that can change depending on dynamic scope. The earmuffs act as a warning that "here be dragons" and to never assume the state of the var. Remember, this is a convention, not a rule.

Core Clojure examples include *out* and *in* which represent the standard in and out streams for Clojure.

>!!, <!!, >!, and <! - core.async channel macros

These symbols are channel operations in core.async - a Clojure/ClojureScript library for channel based asynchronous programming (specifically CSP - Communicating Sequential Processes).

If you imagine, for the sake of argument, a channel is a bit like a queue that things can put stuff on and take stuff off, then these symbols support that simple API.

  • >!! and <!! are blocking put and take respectively

  • >! and <! are, simply put and take

THe difference being the blocking version operate outside go blocks and block the thread they operate on.

user=> (def my-channel (chan 10)) ; create a channel
user=> (>!! my-channel "hello")   ; put stuff on the channel
user=> (println (<!! my-channel)) ; take stuff off the channel
hello

The non-blocking versions need to be executed within a go block, otherwise they’ll throw an exception.

user=> (def c (chan))
#'user/c
user=> (>! c "nope")
AssertionError Assert failed: >! used not in (go ...) block
nil  clojure.core.async/>! (async.clj:123)

While the difference between these is well outside the scope of this guide, fundamentally the go blocks operate and manage their own resources pausing execution of code without blocking threads. This makes asynchronously executed code appear to be synchronous, removing the pain of managing asynchronous code from the code base.

<symbol>? - Predicate Suffix

Putting ? at the end of a symbol is a naming convention common across many languages that support special characters in their symbol names. It is used to indicate that the thing is a predicate, i.e. that it poses a question. For example, imagine using an API that dealt with buffer manipulation:

(def my-buffer (buffers/create-buffer [1 2 3]))
(buffers/empty my-buffer)

At a glance, how would you know if the function empty in this case,

  • Returned true if the passed in buffer was empty, or,

  • Cleared the buffer

While the author could have renamed empty to is-empty, the richness of symbol naming in Clojure allows us to express intent more symbolically.

(def my-buffer (buffers/create-buffer [1 2 3]))
(buffers/empty? my-buffer)
false

This is simply a recommended convention, not a requirement.

<symbol>! - Unsafe Operations

The names of functions/macros that are not safe in STM transactions should end with an exclamation mark (e.g reset!).

You’ll most commonly see this appended to function names whose purpose is to mutate state, e.g. connecting to a data store, updating an atom or closing a file stream

user=> (def my-stateful-thing (atom 0))
#'user/my-stateful-thing
user=> (swap! my-stateful-thing inc)
1
user=> @my-stateful-thing
1

This is simply a recommended convention and not a requirement.

Note that the exclamation mark is often pronounced as bang.

_ - Unused argument

When you see the underscore character used as function arguments or in a let binding, _ is a common naming convention to indicate you won’t be using this argument.

This is an example using the add-watch function that can be used to add callback style behaviour when atoms change value. Imagine, given an atom, we want to print the new value every time it changes:

(def value (atom 0))

(add-watch value nil (fn [_ _ _ new-value]
                       (println new-value))

(reset! value 6)
; prints 6
(reset! value 9)
; prints 9

add-watch takes four arguments, but in our case we only really care about the last argument - the new value of the atom so we use _ for the others.

, - Whitespace character

In Clojure, , is treated as whitespace, exactly the same as spaces, tabs, or newlines. Commas are thus never required in literal collections, but are often used to enhance readability:

user=>(def m {:a 1, :b 2, :c 3}
{:a 1, :b 2, :c 3}

#= Reader eval

#= allows the reader to evaluate an arbitrary form during read time:

user=> (read-string "#=(+ 3 4)")
;;=> 7

Note that the read-time evaluation can also cause side-effects:

user=> (read-string "#=(println :foo)")
:foo
nil

Consequently, read-string is not safe to call with unverified user input. For a safe alternative, see clojure.edn/read-string.

Note that #= is not an officially supported feature of the reader, so you shouldn’t rely on its presence in future versions of Clojure.

Many thanks to everyone who has contributed ideas and [the copious amounts of] spelling corrections (crikey I’m bad at speelingz - so thanks Michael R. Mayne, lobsang_ludd). I’ve tried to call out people who have specifically asked for things. Sorry if I’ve missed you.