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
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With