Search code examples
clojure

Why does the clojure repl show that a var is associated with a symbol, after it's been unmapped?


Let's say I create a variable, x, in a Clojure namespace, store the associated var in another variable (y), and then unmap x:

(ns user)
(def x 0) 
(def y (var x))
(ns-unmap 'user 'x)

If I evaluate y in the REPL, it prints #'user/x, even though the symbol user/x is not associated with this variable anymore.

user=> y
#'user/x
user=> (deref y)
0
user=> (deref #'user/x)
Syntax error compiling var at (REPL:0:0).
Unable to resolve var: user/x in this context

Things get really confusing if I create a new variable associated with the symbol x:


(def x 1)
(def z (var x))

Now, the repl prints both y and z as #'user/x, even though those variables point to different var objects:

user=> y
#'user/x
user=> (deref y)
0
user=> z
#'user/x
user=> (deref z)
1
user=> (= z y)
false

Why does the REPL print #'user/x when evaluating y here?


Solution

  • To think properly about this, you need to understand how vars and namespaces work in Clojure.

    • A var is a mutable storage location, optionally named by a namespaced symbol.
    • A namespace is a map from symbol to var.
    • If namespace n has a definition named s, then it maps the symbol n/s to a var that is named by n/s.

    So, you defined x, yielding a var (call it v) labeled user/x and containing 0, and stored in the namespace user. Then you removed that mapping from the user namespace. But the var v still exists, and still knows it's called user/x. So you can still look at it by traversing through y, which has of course saved the actual var object, and no longer cares what namespace was used to look up the var. You can, e.g. print its name and dereference it to see the value 0 that was locked in there.

    You later define a new var named x in the user namespace, yielding a new var that knows it's referred to by user/x. But it's a distinct var, so they can hold different values, and the user namespace now points to a different var than the one you stored in y.