Just a quick PSA on a topic I don’t think I’ve heard about anywhere else: the term “namespace” in Clojure.
“Namespace” means at least two things in Clojure, and they often overlap. The first meaning is the one you’re likely thinking of: the namespaces by which we organize code, that vars live in. This is the sort of namespace referred to by the
clojure.core functions and macros that have
ns in the name (
*ns*, …), as well as several that contain
namespace spelled out. The notable exception is
user> (doc namespace) ------------------------- clojure.core/namespace ([x]) Returns the namespace String of a symbol or keyword, or nil if not present.
This actually doesn’t strictly have anything to do with the first meaning of “namespace”. It refers to the part of symbols and keywords preceding the
/ if present. E.g.,
user> (namespace :foo) nil user> (namespace 'bar) nil user> (namespace ::bam) "user" user> (namespace :flaz.bang/chizzle) "flaz.bang" user> (namespace `taco-sam) "user" user> (namespace #'first) ClassCastException clojure.lang.Var cannot be cast to clojure.lang.Named user> (namespace second) ClassCastException clojure.core$second cannot be cast to clojure.lang.Named
What tends to confuse the issue is that though the two don’t have to have anything to do with each other, they often do. For example, if I enter:
user> (clojure.string/trim " HOITS") "HOITS"
I’ve written code that syntactically contains a symbol with the namespace
"clojure.string", and the compiler uses this when resolving the symbol to figure out that it needs to look for a var interned under the name
trim in the
clojure.string namespace. But we all know that we may well have done something like this:
(ns user (:require [clojure.string :as s])) (s/join " and " ["you" "me" "me" "you"]) ;; => "you and me and me and you"
In this case we’re using the symbol
s/join in the code, and even though we know that it’s referring to the
#'clojure.string/join var, the actual namespace of the symbol in the code is not
(namespace 's/join) ;; => "s"
The compiler is letting us use this symbol even though there is no namespace (in the normal sense) called
namespace function actually complements the
(for [x [:foo 'bar :baz.bang/toots 'fizzle/wizzle]] [x (namespace x) (name x)]) ([:foo nil "foo"] [bar nil "bar"] [:baz.bang/toots "baz.bang" "toots"] [fizzle/wizzle "fizzle" "wizzle"])
In summary, both symbols and keywords can have “namespaces” which may or may not match an existing “code-namespace” (and there are uses for all four possibilities).