Should intern obey :dynamic?

82 views
Skip to first unread message

Brian Marick

unread,
Oct 12, 2011, 3:48:28 PM10/12/11
to clo...@googlegroups.com
Consider this ordinary way of defining a dynamic variable:

user=> (def ^:dynamic *dynamo* 3)

As you'd expect, you can rebind:

user=> (binding [*dynamo* "new value"] *dynamo*)
"new value"

The metadata tells you why:

user=> (meta #'*dynamo*)
{:ns #<Namespace user>, :name *dynamo*, :dynamic true, :line 1, :file ...}

Now let's make another variable with `intern`, copying the metadata from `*dynamo*`:

user=> (intern *ns* (with-meta '*copy* (meta #'*dynamo*)) *dynamo*)

Same metadata (except for the name):

user=> (meta #'*copy*)
{:ns #<Namespace user>, :name *copy*, :dynamic true, :line 1, :file ...}

But you can't rebind:

user=> (binding [*copy* "new value"] *copy*)
IllegalStateException Can't dynamically bind non-dynamic var: user/*copy* clojure.lang.Var.pushThreadBindings (Var.java:339)

Bug?


-----
Brian Marick, Artisanal Labrador
Now working at http://path11.com
Contract programming in Ruby and Clojure
Occasional consulting on Agile


Armando Blancas

unread,
Oct 12, 2011, 4:49:16 PM10/12/11
to Clojure
> The metadata tells you why:
>
>     user=> (meta #'*dynamo*)
>     {:ns #<Namespace user>, :name *dynamo*, :dynamic true, :line 1, :file ...}

The var tells you why:
user=> (.isDynamic (var *dynamo*))
true

>
> Now let's make another variable with `intern`, copying the metadata from `*dynamo*`:
>     user=> (intern *ns* (with-meta '*copy* (meta #'*dynamo*)) *dynamo*)
> Same metadata (except for the name):
>     user=> (meta #'*copy*)
>     {:ns #<Namespace user>, :name *copy*, :dynamic true, :line 1, :file ...}
> But you can't rebind:
>     user=> (binding [*copy* "new value"] *copy*)
>     IllegalStateException Can't dynamically bind non-dynamic var: user/*copy*  clojure.lang.Var.pushThreadBindings (Var.java:339)

user=> (.isDynamic (var *copy*))
false
user=> (.setDynamic (var *copy*))
#'user/*copy*
user=> (binding [*copy* "new value"] *copy*)
"new value"

Brian Marick

unread,
Oct 12, 2011, 6:02:48 PM10/12/11
to clo...@googlegroups.com

On Oct 12, 2011, at 3:49 PM, Armando Blancas wrote:

>> The metadata tells you why:
>>
>> user=> (meta #'*dynamo*)
>> {:ns #<Namespace user>, :name *dynamo*, :dynamic true, :line 1, :file ...}
>
> The var tells you why:
> user=> (.isDynamic (var *dynamo*))
> true

The mere human who has not read Var.java is not going to know about its methods (or are they a documented part of the interface?) The debugging-person presented with a variable that's not behaving dynamically might well look at the metadata to see what's up.

>
> user=> (.isDynamic (var *copy*))
> false
> user=> (.setDynamic (var *copy*))
> #'user/*copy*
> user=> (binding [*copy* "new value"] *copy*)
> "new value"

Can you think of a reason why a person might use the `(intern *ns* (with-meta symbol))` idiom and *not* want isDynamic-ness to be copied?

Seems to me that if you're going to use metadata to communicate intention about dynamic binding in *one* way of creating a new var, you should do it with *all* ways of creating a new var.

Armando Blancas

unread,
Oct 12, 2011, 7:55:47 PM10/12/11
to Clojure
> Seems to me that if you're going to use metadata to communicate intention about dynamic binding in *one* way of creating a new var, you should do it with *all* ways of creating a new var.

And you may be right. My point was that a var's dynamic nature is part
of its state: it's primarily data, but exists also as metadata (like
static for functions). This kind of thing happens when you keep data
in two places. IMO, metadata isn't the right way to enter modifiers;
an optional symbol might be better.
Reply all
Reply to author
Forward
0 new messages