47
votes

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?

  1. The symbol gets qualified to a namespace, in this case clojure.core
  2. Then in some symbol table there is the information that + refers to a var
  3. When this var is evaluated, the result is a function-value?
5
you seem to understand this quite well :)Arthur Ulfeldt

5 Answers

66
votes

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
8
votes

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.

7
votes

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:

  1. + is a symbol sitting in clojure.core which is by default accessible to your code.
  2. 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.
  3. 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.

0
votes

I find an understanding of the difference between symbols, functions, literals, and vars is necessary to grok what's happening.

  1. (def one (fn [] 1))#'example/one. It references the function #function[example/one]
  2. (def x one)#'example/x references the function #function[example/one]
  3. (def y 'one)#'example/y references the symbol one
  4. (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:

  1. (type one)example$one
  2. (type x)example$one
  3. (type y)clojure.lang.Symbol
  4. (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.

  1. (one)1
  2. (x)1
  3. (y) ⇒ unrelated associative lookup error
  4. (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)).

  1. (one)2 ← new value
  2. (x)1original value
  3. (y) ⇒ unrelated associative lookup error
  4. (z)2new value

Following the logic of symbol → var → value:

  • x(var x)(defn one [] 1)
    1. x resolves to (var x) ("the global var named by the symbol")
    2. (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).
    1. z resolves to its var, which dereferences to (var one)
    2. 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.

0
votes

call

(ns-map *ns*)

to get a map of all available symbols in your namespace and vars they are pointing to