The next thing we need to look at are symbols, keywords and namespaces. Symbols and keywords are used to name things, and the Clojure versions are a bit different from how they work in Common Lisp. In Common Lisp, there is a notion of a package, which is a lot like a Clojure namespace, and there are symbols which have a name and are maybe affiliated with a package. The Clojure version of a symbol has a name and may have a namespace, but the namespace may not exist even if it is present in the symbol.

We can make symbols using the symbol function

user=> (symbol "foo" "bar")

foo/bar

user=> (symbol "bar")

bar

And use the namespace and name functions to deconstruct them

user=> (namespace (symbol "foo" "bar"))

"foo"

user=> (name (symbol "foo" "bar"))

"bar"

user=> (namespace (symbol "bar"))

nil

user=> (name (symbol "bar"))

"bar"

Rather than using the function symbol to make the symbol, the reader automatically makes the symbol when it reads it.

user=> (name ‘bar)

"bar"

user=> (namespace ‘bar)

nil

user=> (name ‘foo/bar)

"bar"

user=> (namespace ‘foo/bar)

"foo"

In Common Lisp, Keywords are symbol with a particular home package – the package that owns the symbol is the package named Keyword. In Clojure, a Keyword is an instance of a class which contains a symbol.

user=> (keyword "foo" "bar")

:foo/bar

user=> (namespace :foo/bar)

"foo"

user=> (name :foo/bat)

"bat"

user=> (keyword "bar")

:bar

user=> (namespace :bar)

nil

user=> (name :bar)

"bar"

Keywords are useful because they evaluate to themselves, whereas symbols are evaluated by looking them up and evaluating the result of this lookup.

user=> :boo

:boo

user=> boo

java.lang.Exception: Unable to resolve symbol: boo in this context (NO_SOURCE_FILE:0)

Just before we look at any more code, remember than the String class in java has an intern method that converts a string to a canonical instance of the same string.

user=> (. (new String "a") (intern))

"a"

user=> (new String "a")

"a"

user=> (identical? *1 *2)

false

user=> (new String "a")

"a"

user=> (new String "a")

"a"

user=> (identical? (new String "a") "a")

false

user=> (. (new String "a") (intern))

"a"

user=> (. (new String "a") (intern))

"a"

user=> (identical? *1 *2)

true

The Symbol class always interns the strings used for the namespace and the name to make later comparison identity comparison instead of equality comparison.

static public Symbol intern(String ns, String name){

return new Symbol(ns == null ? null : ns.intern(), name.intern());

}

static public Symbol intern(String nsname){

int i = nsname.lastIndexOf(‘/’);

if(i == -1)

return new Symbol(null, nsname.intern());

else

return new Symbol(nsname.substring(0, i).intern(), nsname.substring(i + 1).intern());

}

Symbols have metadata.

user=> (def x ‘a)

#’user/x

user=> x

a

user=> (meta x)

nil

user=> (with-meta ‘a {:a 2})

a

user=> (def y *1)

#’user/y

user=> (meta y)

{:a 2}

And compare equal if their name and namespace components are the same.

user=> (= ‘a ‘a)

true

user=> (identical? ‘a ‘a)

false

In this example, the reader is making a new symbol every time it reads one of the “a” characters.

When the Clojure reader reads something from a file, perhaps prior to compiling it, the forms are read as lists of symbols.

user=> (def form ‘(defn foo [x y] (+ x y)))

#’user/form

user=> (first form)

defn

user=> (namespace (first form))

nil

user=> (name (first form))

"defn"

user=> (namespace (second form))

nil

user=> (name (second form))

"foo"

Namespaces are the next thing we need to understand in order to see how the system evaluates the form contained in the Var named form. The first symbol, “defn” will be resolved in the current namespace to see if it denotes a Var.

user=> *ns*

#<Namespace user>

user=> (first form)

defn

user=> (resolve (first form))

#’clojure.core/defn

user=> (ns-resolve *ns* (first form))

#’clojure.core/defn

The Java class for Namespace contains the following fields.

public class Namespace extends AReference{

final public Symbol name;

final AtomicReference<IPersistentMap> mappings = new AtomicReference<IPersistentMap>();

final AtomicReference<IPersistentMap> aliases = new AtomicReference<IPersistentMap>();

final static ConcurrentHashMap<Symbol, Namespace> namespaces = new ConcurrentHashMap<Symbol, Namespace>();

The namespace is named by a Symbol and there is a global map of symbols to namespaces. Each namespace has a group of mappings and some aliases.

When a namespace is constructed in the java code, the constructor deals with metadata, sets the name of the namespace, sets the aliases to an empty map and initializes the mappings to a default set.

Namespace(Symbol name){

super(name.meta());

this.name = name;

mappings.set(RT.DEFAULT_IMPORTS);

aliases.set(RT.map());

}

The mappings of a namespace. accessed by the Clojure function ns-map, maps from symbols to Var or Class instances.

user=> (ns-map (find-ns ‘user))

{sorted-map #’clojure.core/sorted-map, read-line #’clojure.core/read-line, re-pattern #’clojure.core/re-pattern, keyword? #’clojure.core/keyword?, val #’clojure

.core/val, ProcessBuilder java.lang.ProcessBuilder, Enum java.lang.Enum, SuppressWarnings java.lang.SuppressWarnings, *compile-path* #’clojure.core/*compile-path*,par #’user/par, max-key #’clojure.core/max-key, list* #’clojure.core/list*, ns-aliases #’clojure.core/ns-aliases, the-ns #’clojure.core/the-ns, == #’clojure.core/==, longs #’clojure.core/longs, special-form-anchor #’clojure.core/special-form-anchor, Throwable java.lang.Throwable, InterruptedException java.lang.InterruptedException, instance? #’clojure.core/instance?, syntax-symbol-anchor #’clojure.core/syntax-symbol-anchor, Thread$UncaughtExceptionHandler java.lang.Thread$UncaughtExceptionHandler, RuntimeException java.lang.RuntimeException, …..}

RT.DEFAULT_IMPORTS is a mappings consisting of a large number of predefined Java classes.

final static IPersistentMap DEFAULT_IMPORTS = map(

Symbol.create("Boolean"), Boolean.class,

Symbol.create("Byte"), Byte.class,

Symbol.create("Character"), Character.class,

Symbol.create("Class"), Class.class,

Symbol.create("ClassLoader"), ClassLoader.class,

Symbol.create("Compiler"), Compiler.class,

Symbol.create("Double"), Double.class,

Symbol.create("Enum"), Enum.class,

Symbol.create("Float"), Float.class,

………… }

Hence, all newly created namespaces start with these mappings.

user=> (find-ns ‘myNamespace)

nil

user=> (create-ns ‘myNamespace)

#<Namespace myNamespace>

user=> (find-ns ‘myNamespace)

#<Namespace myNamespace>

user=> (ns-resolve (find-ns ‘myNamespace) ‘Boolean)

java.lang.Boolean

user=> (ns-resolve (find-ns ‘myNamespace) ‘boolean)

nil

The Namespace class supports methods all, remove, find, findOrCreate for accessing a sequence of all known namespaces and for adding and removing from this set.

user=> (all-ns)

(#<Namespace clojure.set> #<Namespace user> #<Namespace clojure.main> #<Namespace clojure.core> #<Namespace clojure.zip> #<Namespace clojure.xml>)

user=> (create-ns ‘foo)

#<Namespace foo>

user=> (all-ns)

(#<Namespace clojure.set> #<Namespace user> #<Namespace clojure.main> #<Namespace clojure.core> #<Namespace clojure.zip> #<Namespace foo> #<Namespace clojure.xml>)

user=> (remove-ns ‘foo)

#<Namespace foo>

user=> (all-ns)

(#<Namespace clojure.set> #<Namespace user> #<Namespace clojure.main> #<Namespace clojure.core> #<Namespace clojure.zip> #<Namespace clojure.xml>)

user=> (find-ns ‘clojure.core)

#<Namespace clojure.core>

user=> (find-ns ‘foo)

nil

Symbols can be interned into a namespace in order to make a named Var binding.

user=> (create-ns ‘foo)

#<Namespace foo>

user=> (intern (find-ns ‘foo) ‘bar)

#’foo/bar

This uses one of the intern methods on Var

public static Var intern(Symbol nsName, Symbol sym){

Namespace ns = Namespace.findOrCreate(nsName);

return intern(ns, sym);

}

which calls back into the intern method on the Namespace

public static Var intern(Namespace ns, Symbol sym){

return ns.intern(sym);

}

which does the actual work

public Var intern(Symbol sym){

if(sym.ns != null)

{

throw new IllegalArgumentException("Can’t intern namespace-qualified symbol");

}

IPersistentMap map = getMappings();

Object o;

Var v = null;

while((o = map.valAt(sym)) == null)

{

if(v == null)

v = new Var(this, sym);

IPersistentMap newMap = map.assoc(sym, v);

mappings.compareAndSet(map, newMap);

map = getMappings();

}

if(o instanceof Var && ((Var) o).ns == this)

return (Var) o;

throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name);

}

Lookup of a symbol in a namespace is via the resolve function (which will use the current namespace, that in the *ns* Var)

user=> (resolve ‘foo/bar)

#’foo/bar

The functions implementing this are in core.clj

(defn resolve

"same as (ns-resolve *ns* symbol)"

[sym] (ns-resolve *ns* sym))

(defn ns-resolve

"Returns the var or Class to which a symbol will be resolved in the

namespace, else nil. Note that if the symbol is fully qualified,

the var/Class to which it resolves need not be present in the

namespace."

[ns sym]

(clojure.lang.Compiler/maybeResolveIn (the-ns ns) sym))

Symbols from one namespace can be made visible in another.

user=> (ns-resolve ‘foo ‘mySym)

nil

user=> (create-ns ‘other)

#<Namespace other>

user=> (intern ‘other ‘mySym)

#’other/mySym

user=> (binding [*ns* (find-ns ‘foo)] (refer ‘other))

nil

user=> (ns-resolve ‘foo ‘mySym)

#’other/mySym

user=> (ns-resolve ‘foo ‘other/mySym)

#’other/mySym

Internally this calls the refer method of the Namespace object

public Var refer(Symbol sym, Var var){

return (Var) reference(sym, var);

}

which calls the reference method

Object reference(Symbol sym, Object val){

if(sym.ns != null)

{

throw new IllegalArgumentException("Can’t intern namespace-qualified symbol");

}

IPersistentMap map = getMappings();

Object o;

while((o = map.valAt(sym)) == null)

{

IPersistentMap newMap = map.assoc(sym, val);

mappings.compareAndSet(map, newMap);

map = getMappings();

}

if(o == val)

return o;

throw new IllegalStateException(sym + " already refers to: " + o + " in namespace: " + name);

}

Import can be used to map java classes into a namespace. ns-unmap can be used to remove any existing mapping.

user=> Thread

java.lang.Thread

user=> (ns-unmap *ns* ‘Thread)

nil

user=> Thread

java.lang.Exception: Unable to resolve symbol: Thread in this context (NO_SOURCE

_FILE:0)

user=> (import ‘(java.lang Thread))

nil

user=> Thread

java.lang.Thread

One can also set up aliases for a given namespace to allow it to be accessed via another symbol when that symbol is used as the namespace part of the lookup symbol. There are also function ns-publics and ns-imports for getting subsets of the main namespace map.