Namespaces are the means by which you divide your Clojure code into logical groups, similar to packages in Java or modules in other languages. Almost every Clojure source file begins with a namespace declaration using the ns
macro. The following code is an example of a namespace declaration:
(ns clojure.contrib.gen-html-docs (:require [clojure.contrib.duck-streams :as duck-streams]) (:use (clojure.contrib seq-utils str-utils repl-utils def prxml)) (:import (java.lang Exception) (java.util.regex Pattern)))
Fundamentally, a namespace is just a Clojure map. The keys of the map are Clojure symbols and the values are either Clojure Vars or Java classes. The Clojure compiler uses that map to figure out the meaning of each symbol in your source code. Special functions allow you to add, remove, or change entries in the namespace map.
The ns
macro has dozens of options for configuring a namespace, so before tackling it you should understand the lower level functions on which it is based.
Whenever you are working at the Clojure REPL, the REPL prompt tells you that you are "in" a particular namespace. Clojure always starts in the user
namespace:
user=>
Any symbols you define will be created in the user
namespace. You can switch to a different namespace with the in-ns
function:
user=> (in-ns 'greetings) #<Namespace greetings> greetings=>
in-ns
takes a symbol argument, and switches to the namespace named by the symbol, creating it if it does not already exist. Please notice in the example that the symbol greetings
was quoted to prevent Clojure from trying to evaluate it.
A newly-created namespace does not have any symbols in it, not even the core language functions. If you try to call a built-in Clojure function, you will get an error:
greetings=> (println "Hello, World!") java.lang.Exception: Unable to resolve symbol: println in this context
Clojure's built-in functions are defined in the namespace clojure.core
, and you can refer to them from your new namespace by qualifying the symbols with their namespace:
greetings=> (clojure.core/println "Hello, World!") Hello, World! nil
To avoid having to qualify all the symbols you use, you can refer another namespace with the refer
function, which is also defined in clojure.core
:
greetings=> (clojure.core/refer 'clojure.core) nil
Now you can call functions in clojure.core directly, without qualification:
greetings=> (println "Hello, World!") Hello, World! nil
refer
takes a symbol argument and maps all the public symbols from that namespace into the current namespace. (We will cover the difference between public and private symbols later in the section "Public and Private Vars.") The symbols are still mapped to the values in their original namespace. By calling refer
in the example, you created a namespace mapping from the symbol greetings/println
to the Var # 'clojure .core/println
.
refer
takes additional options that specify filters for the symbols to be referred. The options take the form of a keyword followed by a list or map of symbols. The :exclude
option is followed by a (quoted) list of symbols that should not be referred into the current namespace. For example, the following code:
(refer 'clojure.core :exclude '(map set))
This refers all the symbols in the clojure.core
namespace, except map
and set
. You can then define your own versions of map
and set
that do not clash with the original definitions in clojure.core
.
The :only
option is also followed by a list of symbols, but it specifies that only the symbols in the list you specify should be referred into the current namespace. For example, the following code:
(refer 'clojure.core :only '(println prn))
This refers only the two symbols println
and prn
from clojure.core
; other symbols in clojure.core
must still be namespace-qualified, like clojure.core/def
.
Lastly, refer
allows you to rename some symbols when referring them, by including the :rename
keyword followed by a map from symbols in the original namespace to symbols in the current namespace.
(refer 'clojure.core :rename {'map 'core-map, 'set 'core-set})
This refers all symbols from clojure.core
, but makes the symbol clojure.core/map
available in the current namespace as core-map
and clojure.core/set
available as core-set
. This might be useful if you want to define your own version of a built-in function that calls the original version.
As an alternative to copying the mappings from one namespace, you can create a local alias to another namespace, so you can refer to it by a shorter name. Namespace aliases are created with the alias
function:
(alias local-name namespace-name
)
The arguments local-name
and namespace-name
are both (quoted) symbols. alias
creates an alias in the current namespace to the named namespace. After calling alias
, you can reference symbols in the other namespace using local-name
, instead of the full namespace name. For example, the following code:
greetings> (alias 'set 'clojure.set) nil greetings> (set/union #{1 3 5} #{2 3 4}) #{1 2 3 4 5}
refer
and alias
allow you to reference symbols in namespaces that already exist. But what about namespaces defined in other files, including files that haven't been loaded yet? Clojure provides a variety of functions for loading code from files.
The simplest load function is load-file
:
(load-file name
)
load-file
takes one argument, a file name, and attempts to read and evaluate every Clojure form in the file. The file name is given as a String, including any directories, and is interpreted in the context of the current working directory (the directory in which you started Clojure). On a Unix-like system, it might look like the following:
(load-file "path/to/file.clj")
On Windows, back-slashes must be escaped, because the file name is a String:
(load-file "C:\Documents\file.clj")
If you want to load code from some other source, such as a network connection, you can use the load-reader
function, which takes a java.io.Reader
as its argument, and reads and evaluates code from the Reader
.
The Java Virtual Machine uses a special variable called the classpath, a list of directories from which to load executable code. Clojure programs also use the classpath to search for source files.
The classpath is normally specified on the Java command line as a set of directories and JAR files. The following example, for Unix-like systems, creates a classpath consisting of the Clojure JAR and the / code/sources
directory.
java -cp clojure.jar:/code/sources clojure.main
Java development environments and build-management tools usually have their own methods for configuring the classpath; consult your tools' documentation for more information.
Clojure namespaces follow similar naming conventions to Java packages: they are organized hierarchically with parts separated by periods. A popular convention is to name your libraries using the reversed form of an Internet domain name that you control. So if you work for www.example.com
, your namespaces might be named com.example.one, com.example.two, and so on.
When translating between namespace names and file names, periods become directory separators and hyphens become underscores. So, on Unix-like systems, the Clojure namespace com.example.my-cool-library
would be defined in the file com/example/my_cool_library.clj
. In order to load the namespace, the directory containing com
must be on the classpath.
The load
function takes any number of String arguments, each of which names a resource on the classpath. A resource name is like a file name, but without the .clj
extension. If the resource name begins with a forward slash (/), it is interpreted as being in some directory on the classpath. For example, the following code:
(load "/com/example/my_library")
This call will search each location on the classpath for the file com/example/my_library.clj
. (It will also search for the precompiled class file com/example/my_library.class
. Compilation will be covered in Chapter 10.)
If an argument to load
does not begin with a slash, it is interpreted as being relative to the directory of the current namespace.
greetings=> (load "hello")
This call to load
, from within the greetings
namespace, will search the classpath for the file greetings/hello.clj
.
You will rarely use the load
function in normal code. Instead, Clojure provides two higher level functions, require
and use
, to load namespaces.
The require
function takes any number of arguments, each of which is a symbol, a vector libspec, a prefix list, or a flag. Arguments are typically quoted to prevent evaluation. The simplest case, a symbol, converts the symbol to a file name, searches the classpath for that file, loads it, and verifies that a namespace with the given name was, in fact, created.
(require 'com.example.lib)
This loads the file com/example/lib.clj
from the classpath. After loading the file, if the namespace com.example.lib
does not exist, require
will throw an exception. If the namespace has already been loaded, require
will ignore it.
A libspec argument to require
allows you to specify options for loading the namespace. It takes the form of a vector, starting with a symbol, followed by keyword options. The only option it accepts (for now) is :as
, which creates a local alias to the namespace.
(require '[com.example.lib :as lib])
This loads the namespace com.example.lib
and aliases it as lib
in the current namespace.
Often several namespaces share a common prefix. In that case, you can use prefix lists to load several namespaces. A prefix list is a list starting with the symbol shared by all the namespaces, followed by the remaining parts of each namespace name. For example, instead of writing:
(require 'com.example.one 'com.example.two 'com.example.three)
You can write this equivalent:
(require '(com.example one two three))
Prefix lists and libspecs can be combined, as in this example:
(require '(com.example one [two :as t]))
This loads the namespaces com.example.one
and com.example.two
, and creates an alias t
for com.example.two
.
Lastly, the require
function accepts any number of flags, given as keywords anywhere in its arguments. The :reload
flag causes require
to load all namespaces in the arguments, even if they have already been loaded. For example, the following code:
(require 'com.example.one 'com.example.two :reload)
Another flag, :reload-all
, will reload the listed namespaces and all dependent namespaces require
'd by those namespaces. The :reload
and :reload-all
flags are useful when you are experimenting at the REPL and want to load changes you have made in your source files.
The :verbose
flag prints debugging information about the lower-level function calls being made by require
.
user=> (require '(clojure zip [set :as s]) :verbose) (clojure.core/load "/clojure/zip") (clojure.core/load "/clojure/set") (clojure.core/in-ns 'user) (clojure.core/alias 's 'clojure.set) nil
Frequently, you may want to require
a namespace and also refer
certain symbols in it. The use
function makes this a one-step operation. Calling use
is equivalent to calling require
and then refer
. use
accepts the :reload
, :reload-all
, and :verbose
flags of require
; and also the :exclude
, :only
, and :rename
options of refer
, grouped in a vector with the namespace they affect. For example, see the following line of code:
(use '[com.example.library :only (a b c)] :reload-all :verbose)
This (re)loads the namespace com.example.library
and refers the three symbols a
, b
, and c
into the current namespace. Note that you do not need to quote the list (a b c)
because the entire vector is already quoted.
Except when experimenting at the REPL, it is almost always a bad idea to use a namespace without limiting the symbols it refers with :only
. Calling use without :only makes it impossible for readers of your code to know where a particular symbol comes from and can also lead to unexpected name clashes if the use
'd namespace changes.
The last namespace function deals with Java classes. You can always refer to a Java class by its fully-qualified name, such as java.util.Date
. To refer to a class without its package, you can import it.
user=> (import 'java.util.Date) nil user=> (new Date) #<Date Fri Oct 23 16:31:28 EDT 2009>
In Clojure 1.0, import
is a function, so you must quote its arguments, as in the example. Starting with Clojure 1.1, import
is a macro, and its arguments do not need to be quoted. import
also accepts prefix lists similar to require
and use
. The prefix must be a complete Java package name; the class name may not contain periods.
(import '(java.util.regex Pattern Matcher))
As a special case, nested Java classes (sometimes called "inner classes") must be imported using their binary class name, which the JVM uses internally. The binary class name of an inner class consists of the outer class name, followed by a $ sign, followed by the inner class name. For example, the binary name of a class Wheel
nested inside a class Truck
is Truck$Wheel
.
In Clojure, a nested Java class cannot be named without its enclosing class. For example, to import the nested class javax.swing.Box.Filler
, you must do this:
(import '(javax.swing Box$Filler))
After that import, you can refer to the class as Box$Filler
.
When writing normal Clojure code, you will not call the in-ns
, refer
, alias
, load
, require
, use
, and import
functions directly. Instead, you will typically start your Clojure source file with a namespace declaration using the ns
macro, like the example at the start of this chapter.
(nsname
&references
)
The ns
macro takes a symbol as its first argument; it creates a new namespace with that name and sets it to be the current namespace. Because ns
is a macro that does not evaluate its arguments, the name does not need to be quoted.
The remaining arguments to the ns macro take the same form as the refer
, load
, require
, use
, and import
functions, with two differences:
Arguments are never quoted.
The function name is given as a keyword.
Here's an example.
(ns com.example.library (:require [clojure.contrib.sql :as sql]) (:use (com.example one two)) (:import (java.util Date Calendar) (java.io File FileInputStream)))
This creates a new namespace, com.example.library
, and automatically refers the clojure.core
namespace. It loads the clojure.contrib.sql
namespace and aliases it as sql
. It loads the namespaces com.example.one
and com.example.two
and refers all the symbols from them into the current namespace. Finally, it imports the Java classes Date
, Calendar
, File
, and FileInputStream
.
Unlike the in-ns
function, the ns
macro automatically refers the clojure.core
namespace, as previously mentioned. If you want to control which core symbols get referred in your namespace, use the :refer-clojure
argument to ns
, like this:
(ns com.example.library (:refer-clojure :exclude (map set)))
The :refer-clojure
form takes the same arguments that you would use with (refer'clojure.core)
. If you don't want any symbols referred from clojure.core
, you can pass an empty list to :only
, like (:refer-clojure :only ())
.
As previously mentioned, namespaces are essentially maps from symbols to Vars, but they have a few unique properties. Symbols can have properties that tie them to specific namespaces.
Like most Clojure objects, namespaces can have metadata (see Chapter 8) attached to them. You can add metadata to the namespace by placing read-time metadata on the symbol in the ns macro, like this:
(ns #^{:doc "This is my great library." :author "Mr. Quux <[email protected]>" com.example.my-great-library)
While Clojure does not specify any "official" metadata keys for namespaces (like :tag
and :arglists
for functions) many Clojure library developers have adopted the convention of using :doc
metadata to describe the general purpose of a namespace and :author
metadata for the author's name and e-mail address.
The Clojure compiler requires that symbols be defined before they are used. Usually this leads to organizing your source files with simple, low-level functions at the top and more complex functions at the bottom. But sometimes, you need to use a symbol before it can be defined. To prevent the compiler from throwing an Exception, you must use a forward declaration.
(declare & symbols
)
A forward declaration is created with the declare
macro, which simply tells the compiler, "This symbol exists, it will be defined later." Here is a contrived, and very inefficient, example:
(declare is-even? is-odd?) (defn is-even? [n] (if (= n 2) true (is-odd? (dec n)))) (defn is-odd? [n] (if (= n 3) true (is-even? (dec n))))
As you saw earlier, symbols can be qualified with a namespace. The functions name
and namespace
return the strings representing each part of the symbol:
user=> (name 'com.example/thing) "thing" user=> (namespace 'com.example/thing) "com.example"
Notice that the symbol is quoted to prevent Clojure from trying to resolve it as a class or Var.
The namespace
function returns nil
for unqualified symbols, which have no namespace:
user=> (namespace 'stuff) nil
Keywords, too, can be namespace-qualified; the name
and namespace
functions work as on symbols:
user=> (name :com.example/mykey) "mykey" user=> (namespace :com.example/mykey) "com.example" user=> (namespace :unqualified) nil
As a syntactic convenience, you can create keywords in the current namespace by preceding their names with two colons instead of one. In the "user" namespace, the keyword ::thing
expands to :user/thing
.
user=> (namespace ::keyword) "user"
Although not explicitly for this purpose, the backquote `
reader macro can be used to create qualified symbols in the current namespace:
user=> `sym user/sym
The name
and namespace
functions convert from symbols or keywords to strings. The symbol
and keyword
functions go the other way: given Strings for the name and, optionally, a namespace, they construct a symbol or keyword.
user=> (symbol "hello") hello user=> (symbol "com.example" "hello") com.example/hello user=> (keyword "thing") :thing user=> (keyword "user" "goodbye") :user/goodbye
Note that the name given to the keyword
function does not include the leading colon.
By default, all definitions in a namespace are public, meaning they can be referenced from other namespaces and copied with refer
or use
. But many namespaces can be divided into two parts: one set of "internal" functions that should never be called from any other namespace and another set of "public" functions meant for use by other namespaces. These correspond, loosely, to the private and public methods of object-oriented languages like Java.
Private Vars in Clojure will never be copied by refer
or use
, and they cannot be referenced with a namespace-qualified symbol. In effect, they can only be used in the namespace in which they were defined.
There are two ways to create a private Var. The first is the defn-
macro, which works exactly like defn
but creates a private function definition. The second, which works for any definition, is to add :private
metadata to the symbol you are defining.
(def #^{:private true} *my-private-value* 123)
Note that private Vars are never truly hidden; any code can get the value of the Var with (deref (var namespace/name))
. But private Vars prevent you from inadvertently calling a function that you did not mean to be used by other parts of your application.
Unlike Java packages, which are simply a naming device, Clojure namespaces are first-class objects, with dedicated functions to query and manipulate them.
The special Var *ns*
is always bound to the current namespace. It is changed with in-ns
.
The function all-ns
takes no arguments and returns a sequence of all namespaces currently defined.
The set of namespaces is global; you cannot have multiple "instances" of Clojure loading different namespaces in the same JVM. It doesn't really make sense to talk about an "instance" of Clojure, since Clojure is just a compiler, not an interpreter like Jython or JRuby. You can create independent execution contexts using Java classloaders, an advanced Java topic outside the scope of this book.
Two functions help you get from a symbol naming a namespace to the namespace object itself. The find-ns
function takes a symbol argument and returns the namespace with that name; or nil
if no such namespace exists.
Often, you don't care if you're dealing with a namespace object directly or just the symbol naming it. For this purpose, a function called the-ns
will accept either a namespace object, in which case it just returns the namespace; or a symbol, in which case it calls find-ns
. Unlike find-ns
, the-ns
throws an Exception if the namespace does not exist. Most of the functions in this section call the-ns
on their argument, so they may be called with either a namespace object (such as *ns*
) or a quoted symbol.
The ns-name
function returns the name of a namespace as a symbol.
The ns-aliases
function returns a map, from symbols to namespaces, representing all the namespace aliases defined in a namespace.
The ns-map
function returns a map, from symbols to objects (Vars or classes), representing all the mappings in a namespace. Usually, this is more information than you want, so Clojure provides several auxiliary functions that return a subset of the mappings for a namespace. ns-publics
returns mappings for all public Vars; ns-interns
returns mappings for all Vars (both public and private); ns-refers
returns mappings for all symbols referred from other namespaces; and ns-imports
returns mappings for all Java classes.
For example, to get a list of all the public symbols in the clojure.core
namespace, you can run:
(keys (ns-publics 'clojure.core))
Finally, you may want to find out what a symbol will resolve to when it is encountered in a particular context. The ns-resolve
function takes a namespace and a symbol, and returns the Var or class to which that symbol is mapped in the namespace. For example, clojure.core
imports the java.math.BigDecimal
class, which you can discover by calling:
user> (ns-resolve 'clojure.core 'BigDecimal) java.math.BigDecimal
As a shortcut, the resolve
function is equivalent to ns-resolve
for the current namespace.
The in-ns
function and ns
macro both create a namespace and make it the current namespace. Likewise, def
and its relatives all operate in the current namespace. There are some special cases, like code generation, where you want to create a namespace and define things in it without switching to it. You may be tempted to write something like this:
;; Bad code! (let [original (ns-name *ns*)] (ns other) (defn f [] (println "Function f") (in-ns original)))
That won't work, because Clojure reads the symbol f
in the current namespace before evaluating the ns
form. You'll end up with f
defined in the current namespace, not the other
namespace.
Instead, you can use the create-ns
function, which takes a symbol argument and returns a new namespace with that name (or returns an existing namespace with that name). Then you can use the intern
function to define Vars in that namespace. Here's a version of the previous example that actually works:
(let [other-ns (create-ns 'other)] (intern other-ns 'f (fn [] (println "Function f"))))
The act of creating a Var and mapping it to a symbol in a namespace is called interning the Var, and that's exactly what the intern
function does.
(intern namespace symbol value
)
The value is optional; if it is omitted, the Var is created with no root value, similar to a forward declaration. The symbol must be a bare symbol, that is, without a namespace-qualifying prefix. The namespace argument may be either a symbol or a namespace.
The ns-unmap
function is the opposite of intern
; it removes a mapping from a namespace. For example, every Clojure namespace, regardless of how it is created, starts with mappings for all the classes in the java.lang
package. If you wanted a completely empty namespace, you could create one like this:
(let [empty-ns (create-ns 'empty)] (doseq [sym (keys (ns-map empty-ns))] (ns-unmap empty-ns sym)) empty-ns)
Finally, the remove-ns
function will delete a namespace entirely, including all the Vars interned in it. Note that code in other namespaces may still hold references to those Vars in closures, but the Vars themselves are cleared, so any attempt to use them will throw an "unbound Var" Exception.
As I said at the beginning of the chapter, a namespace is basically a map from symbols to Vars or classes. It would be more accurate to say it is a reference to a map, because namespaces are mutable. All operations on namespaces are atomic, like Clojure Atoms. For example, if you redefine an existing function with defn
, Clojure guarantees that the old and new definitions will never "overlap."
However, Clojure does not provide a way to coordinate namespace operations the way you can with Refs. If you redefine several functions, Clojure cannot guarantee that the "new" functions will all be updated at the same time. There may be a short time in which both old and new definitions are present.
In general, the problem of "hot-swapping" entire modules in a running program is very difficult, and requires support at the deepest levels of the language. Erlang, for example, is designed to support hot-swapping of modules. Java does not have built-in support for hot-swapping, although some Java application servers attempt to provide it.
There's a lot you can do with namespaces, and they may seem overwhelming at first. But in normal, day-to-day coding you only need a few features and conventions.
First, start every source file with a namespace declaration using ns
, using :import
and :use
expressions to describe the classes and namespaces it depends on. Always use the :only
option of :use
to make it clear which symbols you need from the other namespace. Here is a complete example:
(ns com.example.apps.awesome (:use [clojure.set :only (union intersection)] [com.example.library :only (foo bar baz)] [com.example.logger :only (log)]) (:import (java.io File InputStream OutputStream) (java.util Date)))
Don't be afraid to reuse good names just because they are part of clojure.core
. Add the :refer-clojure
expression to ns
if needed.
Structure your source files to avoid the need for forward declarations. This usually means placing "primitive" definitions near the top and the "composite" definitions that depend on them toward the bottom.
52.15.74.25