Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't change/establish root binding of: [some-def] with set in Clojure

I could not set my dynamic var's value to new one.

(def *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)


Also I've added ^:dynamic, which did not work either.

(def ^:dynamic *pop* true)

(set! *pop* false)

=> IllegalStateException Can't change/establish root binding of: *pop* with set  clojure.lang.Var.set (Var.java:221)


But on the other hand this code works,(clojure core's var -> *warn-on-reflection*)

(set! *warn-on-reflection* true)
=> true

*warn-on-reflection*
=> true

(set! *warn-on-reflection* false)
=> false

*warn-on-reflection*
=> false
like image 899
Ertuğrul Çetin Avatar asked Feb 12 '17 23:02

Ertuğrul Çetin


2 Answers

Dynamic vars can only be set! inside a binding scope. So just calling set! on *pop* won't work - you need to be in the runtime dynamic scope of a binding somewhere in the call stack above.

(def ^:dynamic *pop* true)
(binding [*pop* *pop*]  ;; defaulted to the root binding value
  (set! *pop* false)    ;; ok, because in dynamic binding scope
  (println *pop*))      ;; prints "false" (inside per-thread dynamic binding)
(println *pop*)         ;; prints "true" (root value)

Note that the "dynamic scope" part of it means that within binding you can make arbitrary nested calls and still have access to set and read the per-thread value of *pop*.

Regarding *warn-on-reflection*, this looks like special behavior but it's actually exactly the same, except hidden from view. The REPL itself creates a dynamic binding scope around the eval of each REPL statement with bindings for a hard-coded set of dynamic vars, of which *warn-on-reflection* is one. You can find that set of bindings here.

like image 158
Alex Miller Avatar answered Oct 23 '22 02:10

Alex Miller


You can use alter-var-root to change the root vars.

user=> (def *pop* true)
Warning: *pop* not declared dynamic ...
#'user/*pop*

user=> (alter-var-root #'*pop* (constantly false))
false

user=> *pop*
false
like image 42
ymonad Avatar answered Oct 23 '22 02:10

ymonad