Reputation: 34870
I'm always a bit confused about Symbols and Vars in Clojure. For example, is it safe to say that + is a symbol which is used to denote a var, and this var points to a value which is a function that can add numbers?
So what happens, step by step when I just enter "+" in a REPL?
Upvotes: 48
Views: 6941
Reputation: 905
call
(ns-map *ns*)
to get a map of all available symbols in your namespace and vars they are pointing to
Upvotes: 0
Reputation: 1178
I find an understanding of the difference between symbols, functions, literals, and vars is necessary to grok what's happening.
(def one (fn [] 1))
⇒ #'example/one
. It references the function #function[example/one]
(def x one)
⇒ #'example/x
references the function #function[example/one]
(def y 'one)
⇒ #'example/y
references the symbol one
(def z #'one)
⇒ #'example/z
references the var #'example/one
To put it precicely one
is a symbol that resolves to the var #'example/one
. The var references a function, #function[example/one]
, which returns the literal 1
.
Each def
yields a var. The var is denoted by the #'
syntax in #'example/x
. Each var references a value.
According to Clojure's own documentation, symbols resolve to a value, a special form, or an error when evaluated. So it can be a little confusing because there is no mention of a var:
(type one)
⇒ example$one
(type x)
⇒ example$one
(type y)
⇒ clojure.lang.Symbol
(type z)
⇒ clojure.lang.Var
In the cases above, the value "is the value of the binding of the global var named by the symbol." As another answer stated more succinctly: symbol → var → value.
(one)
⇒ 1
(x)
⇒ 1
(y)
⇒ unrelated associative lookup error(z)
⇒ 1
Remember: #'example/z
references the var #'example/one
. #'example/x
and #'example/y
both reference #function[example/one]
. The significance of this difference is revealed when the original symbol is interned to a new function: (def one (fn [] 2))
.
(one)
⇒ 2
← new value(x)
⇒ 1
← original value(y)
⇒ unrelated associative lookup error(z)
⇒ 2
← new valueFollowing the logic of symbol → var → value:
x
→ (var x)
→ (defn one [] 1)
x
resolves to (var x)
("the global var named by the symbol")(var x)
dereferences the current binding of x
: (fn [] 1)
("the binding of the global var named by the symbol")z
→ (var z)
→ (var one)
.
z
resolves to its var, which dereferences to (var one)
one
resolves to its var, which dereferences to (fn [] 2)
One final note. #'example/one
still evaluates and returns a literal (1
or 2
) because the var is in the first position of a list ((z)
). This behavior is similar to placing a keyword in the first position of a list and a map in the second: (:two {:one 1 :two 2})
⇒ 2
.
Upvotes: 0
Reputation: 13746
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 in clojure.core
which is by default accessible to your code.+
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.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.
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.
the answer to the original question is simply: Yes.
Upvotes: 8
Reputation: 44162
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
Upvotes: 69
Reputation: 6681
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.
Upvotes: 8