Difference between Symbols and Vars in Clojure
There's a symbol + that you can talk about by quoting it:
user=> '+
+
user=> (class '+)
clojure.lang.Symbol
user=> (resolve '+)
#'clojure.core/+
So it resolves to #'+, which is a Var:
user=> (class #'+)
clojure.lang.Var
The Var references the function object:
user=> (deref #'+)
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
user=> @#'+
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
(The @ sign is just shorthand for deref.) Of course the usual way to get to the function is to not quote the symbol:
user=> +
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
Note that lexical bindings are a different mechanism, and they can shadow Vars, but you can bypass them by referring to the Var explicitly:
user=> (let [+ -] [(+ 1 2) (@#'+ 1 2)])
[-1 3]
In that last example the deref can even be left out:
user=> (let [+ -] [(+ 1 2) (#'+ 1 2)])
[-1 3]
This is because Var implements IFn (the interface for Clojure functions) by calling deref on itself, casting the result to IFn and delegating the function call to that.
The visibility mechanism used when you define private functions with defn- is based on metadata on the symbol. You can bypass it by referring directly to the Var, as above:
user=> (ns foo)
nil
foo=> (defn- private-function [] :secret)
#'foo/private-function
foo=> (in-ns 'user)
#<Namespace user>
user=> (foo/private-function)
java.lang.IllegalStateException: var: #'foo/private-function is not public (NO_SOURCE_FILE:36)
user=> (#'foo/private-function)
:secret
See the documentation for namespaces:
Namespaces are mappings from simple (unqualified) symbols to Vars and/or Classes. Vars can be interned in a namespace, using def or any of its variants, in which case they have a simple symbol for a name and a reference to their containing namespace, and the namespace maps that symbol to the same var. A namespace can also contain mappings from symbols to vars interned in other namespaces by using refer or use, or from symbols to Class objects by using import.
So basically your steps 1 and 2 are unified: the namespaces are the symbol tables.
And regarding step 3: I like the definition for variables that they're combinations of names of values. The symbol is the variable's name, and evaluating it will result in its value.
This answer is not very different from the other ones, it just doesn't assume you originally wish to learn several new functions and concepts just to understand what's going on:
-
+
is a symbol sitting inclojure.core
which is by default accessible to your code. - When used in your code without any very advanced intents such as quoting it or finding out its class ― clojure will seek the Var which it points to.
- If this Var is a function, when
+
is used in head position of a list, clojure will try to call that function (NullPointerException
if this Var happened not to point at a function). If supplied as an argument to another function, that function may do the same to call it. That's how function calling works.
further comments to round up:
Most or all languages use symbol tables. Being a somewhat dynamic language, Clojure uses this extra layer of indirection (Symbol → Var → function, rather than only Symbol → function) so that dynamically rewriting which function is tied to which symbol ― is more feasible and elegant, and this is sometimes a source of curiosity for beginners.
As other answers have somewhat overly emphasized, you may otherwise perform fancy stuff like quote it ('+
) to avoid its evaluation, or even inspect it with class
and/or resolve
as if you are interested in verifying what it is (class
), or which namespace it sits in (resolve
). You can also poke at the var it points at via var
or #'
. You'll typically do those fancy things if you are writing macros or if you're very experimentally inclined, especially when working in the repl; depending on which style you write your macros, you might actually quote quite a lot in them.
and a fancy illustration for the extra-exploratory person:
Being a somewhat flexible language, clojure exposes api for taking the Symbol → Var → function walk on your own. You'd not typically ever do that for just using a function, because obviously that would be boring and redundant, but it can be used here to illustrate the process:
(deref (resolve '+))
Namely, the symbol is first resolved to its Var, then the thing that the Var points to, is arrived at. This just illustrates the 2-step process for arriving at a function (Symbol → Var → function), which happens behind the scenes. I hope you've avoided reading this extra part.
TL;DR
the answer to the original question is simply: Yes.