Reputation: 1642
I'm learning Clojure and am playing around with dynamic scope. I've discovered a few things:
{:dynamic true}
metadata to an existing Var doesn't actually make the Var dynamic. I can kind of see why you'd want this to be the case, but it can be misleading.(.isDynamic #'whatever)
(.setDynamic #'whatever)
In short, it looks like the dynamic nature of a Var is stored in the guts of the clojure.lang.Var class itself, and setting ^:dynamic
metadata at def time only will affect that internal state. Changing metadata afterward doesn't appear to affect it. OK, fine.
I discovered this when I was looking at the dynamic variables in namespace clojure.core. I checked to see what Vars in that namespace have :dynamic
metadata set:
user=> (def metadyn (map key (filter #(-> % key resolve meta :dynamic) (ns-publics 'clojure.core))))
#'user/metadyn
user=> metadyn
(*3 *2 *print-level* *data-readers* *e *print-length* *1 *verbose-defrecords*
*clojure-version* *default-data-reader-fn* pr)
Rather fewer than I expected, missing things like *out*
and *in*
.
I checked to see what Vars actually are dynamic:
user=> (def realdyn (map key (filter #(-> % key resolve .isDynamic) (ns-publics 'clojure.core))))
#'user/realdyn
user=> realdyn
(*compile-path* *3 *2 *ns* *print-level* *allow-unresolved-vars* *data-readers*
*unchecked-math* *math-context* *read-eval* *compile-files* *command-line-args*
*warn-on-reflection* *e *flush-on-newline* *out* *print-length* *1 *file* *verbose-defrecords*
*clojure-version* *use-context-classloader* *err* *default-data-reader-fn* *agent* pr
*print-dup* *print-readably* *fn-loader* *print-meta* *in* *source-path* *compiler-options* *assert*)
Lots more.
So, the following Vars are dynamic but don't claim to be in their metadata:
user=> (clojure.set/difference (set realdyn) (set metadyn))
#{*compile-path* *ns* *allow-unresolved-vars* *unchecked-math* *math-context* *read-eval*
*compile-files* *command-line-args* *warn-on-reflection* *flush-on-newline* *out* *file*
*use-context-classloader* *err* *agent* *print-dup* *print-readably* *fn-loader* *print-meta*
*in* *source-path* *compiler-options* *assert*}
My question is simply: is there any significance to this, something I'm missing? Or, is it just a case of sloppy bookkeeping in the Clojure implementation?
No practical use for this; just trying to Understand.
Upvotes: 1
Views: 224
Reputation: 26446
The dynamic vars you have identified without metadata are those created in the Java runtime (see RT.java starting around line 180). The others are created in Clojure after the bootstrapping has made def
available (i.e. within core.clj and core_print.clj).
Metadata could have been added later and in some cases was (e.g. *agent*
has a docstring), so this is not a complete answer. I could speculate that lack of practical importance, as you point out, has made truing-up the metadata of the vars used in bootstrapping a low priority.
Upvotes: 1