Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by
I'm sure 'built in' is probably not the right term here, but I'm not sure what these are called.

I ran into this issue earlier today while fixing a bug in clojail. Built in vars, particularly ones listed here without a source link: http://clojure.github.com/clojure/clojure.core-api.html, do not have :dynamic metadata despite being dynamic. This includes \*in\*, \*out\*, and \*err\* among others. Here are some examples:


user=> (meta #'*err*)
{:ns #<Namespace clojure.core>, :name *err*, :added "1.0", :doc "A java.io.Writer object representing standard error for print operations.\n\n  Defaults to System/err, wrapped in a PrintWriter"}
user=> (meta #'*in*)
{:ns #<Namespace clojure.core>, :name *in*, :added "1.0", :doc "A java.io.Reader object representing standard input for read operations.\n\n  Defaults to System/in, wrapped in a LineNumberingPushbackReader"}
user=> (meta #'*out*)
{:ns #<Namespace clojure.core>, :name *out*, :added "1.0", :doc "A java.io.Writer object representing standard output for print operations.\n\n  Defaults to System/out, wrapped in an OutputStreamWriter", :tag java.io.Writer}
user=> (meta #'*ns*)
{:ns #<Namespace clojure.core>, :name *ns*, :added "1.0", :doc "A clojure.lang.Namespace object representing the current namespace.", :tag clojure.lang.Namespace}

5 Answers

0 votes
by

Comment made by: bsmith.occs@gmail.com

This recent discussion on the users list seems relevant: (link: http://groups.google.com/group/clojure/browse_thread/thread/d5efd00c699f73a7 text: Should intern obey :dynamic?).

It seems to boil down to this the information that a Var is dynamic (or not) is duplicated. Once as metadata with the key {{:dynamic}}, and once as a boolean field on the Var class which implements Clojure's variables. This boolean can be obtained by calling the method {{isDynamic()}} on the Var.

The confusion arises because apparently {{:dynamic}} and {{.isDynamic}} can get out of sync with each other. {{.isDynamic}} is the source of truth in this case.

0 votes
by
_Comment made by: bsmith.occs@gmail.com_

{{Compiler$Parser.parse(...)}} finds the {{:dynamic}} entry left in the metadata of the symbol by {{LispReader}} and passes this on when creating a new {{DefExpr}}, which in turn, generates the code that will call {{setDynamic(...)}} on the var when it is created at runtime.

As far as I can tell, the {{:dynamic}} entry is irrelevant once that has occurred. It seems to be implemented only as a way to communicate (by way of the reader) with the compiler. Once the compiler's gotten the message, it isn't needed anymore. Keeping it around seems to just cause confusion.

Dynamic vars created by the Java layer of Clojure core don't use the {{:dynamic}} mechanism, they just {{setDynamic()}} directly. That's why they don't have {{:dynamic}} in their meta-data map.

- Perhaps the compiler should elide {{:dynamic}} from the metadata map available at runtime, since it has served its purpose.
- Perhaps Clojure should supply the function {{dynamic?}}.
(defn dynamic? [^clojure.lang.Var v] (.isDynamic v))

Or, perhaps one might consider, for 1.4, replacing {{:dynamic}} altogether and just enforcing the established naming convention: {{\*earmuffs\*}} are dynamic, {{everything-else}} isn't. (The compile warns about violations of this convention in 1.3.)
0 votes
by

Comment made by: jafingerhut

I recently noticed several lines like this one in core.clj. Depending upon how many symbols are like this, perhaps this method could be used to add :dynamic metadata to symbols in core, along with a unit test to verify that all symbols in core have :dynamic if and only if .isDynamic returns true?

0 votes
by

Comment made by: jafingerhut

Ugh. In my previous comment, by "several lines like this one" I meant to paste the following as an example:

(alter-meta! #'agent assoc :added "1.0")

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-859 (reported by alex+import)
...