ClojureScript

alter-meta! does not work on vars (documentation issue)

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Major Major
  • Resolution: Unresolved
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

(def foo "foo")
(meta (var foo))
; => {:ns cljs.user, :name foo, :file "<cljs repl>", :end-column 9, :source "foo", :column 1, :line 1, :end-line 1, :arglists (), :doc nil, :test nil}
(alter-meta! (var foo) assoc :foo 42)
(meta (var foo))
;{:ns cljs.user, :name foo, :file "<cljs repl>", :end-column 9, :source "foo", :column 1, :line 1, :end-line 1, :arglists (), :doc nil, :test nil}

This ticket: http://dev.clojure.org/jira/browse/CLJS-1248 did fix vary-meta but not mutating metas in place.

Activity

Hide
Brian Gregg added a comment - - edited

Hmm, I cloned but it won't let me edit.

So the documentation for alter-meta! states that it is supported for Vars:

"Atomically sets the metadata for a namespace/var/ref/agent/atom to be:

(apply f its-current-meta args)

f must be free of side-effects"

But it doesn't work and after looking at the source, the only thing needed to support Vars is to remove the _ from `_meta`:

(defn alter-meta!
[iref f & args]
(set! (.-meta iref) (apply f (.-meta iref) args)))

(deftype Var [val sym _meta]
...
IMeta
(-meta [_] _meta)
...

Show
Brian Gregg added a comment - - edited Hmm, I cloned but it won't let me edit. So the documentation for alter-meta! states that it is supported for Vars: "Atomically sets the metadata for a namespace/var/ref/agent/atom to be: (apply f its-current-meta args) f must be free of side-effects" But it doesn't work and after looking at the source, the only thing needed to support Vars is to remove the _ from `_meta`: (defn alter-meta! [iref f & args] (set! (.-meta iref) (apply f (.-meta iref) args))) (deftype Var [val sym _meta] ... IMeta (-meta [_] _meta) ...
Hide
Brian Gregg added a comment -

After further experimentation, Vars don't behave how I expected. It seems every time a var is referenced (with (var) or with #') the compiler creates a new instance of the var/metadata, so any modifications made to the previous one aren't reflected.

However it works when I store the var in a different var.

For example:

(set! js/window.lhs #'foo)
(set! js/window.rhs #'foo)

In the JS console, lhs !== rhs. But if I do:

(set! js/window.lhs #'foo)
(set! js/window.rhs js/window.rhs)

Then the js console says lhs === rhs is true.

So I guess I have to store my var reference in another def in order to manipulate it as expected?

Show
Brian Gregg added a comment - After further experimentation, Vars don't behave how I expected. It seems every time a var is referenced (with (var) or with #') the compiler creates a new instance of the var/metadata, so any modifications made to the previous one aren't reflected. However it works when I store the var in a different var. For example: (set! js/window.lhs #'foo) (set! js/window.rhs #'foo) In the JS console, lhs !== rhs. But if I do: (set! js/window.lhs #'foo) (set! js/window.rhs js/window.rhs) Then the js console says lhs === rhs is true. So I guess I have to store my var reference in another def in order to manipulate it as expected?
Hide
Thomas Heller added a comment -

CLJS does not use vars at runtime and cannot be modified as such. cljs.core/Var instances are created from the cljs.analyzer data of that var which lives on the CLJ side and thus cannot be modified from CLJS directly without going through macros. It does work if you pass around the var instances once created but cljs.core/var will always create a new instance otherwise.

Show
Thomas Heller added a comment - CLJS does not use vars at runtime and cannot be modified as such. cljs.core/Var instances are created from the cljs.analyzer data of that var which lives on the CLJ side and thus cannot be modified from CLJS directly without going through macros. It does work if you pass around the var instances once created but cljs.core/var will always create a new instance otherwise.
Hide
Brian Gregg added a comment -

Yes, I did figure that out after a few hours of trial and error.

So can the alter-meta! documentation be updated to remove mention of vars? Also, it would be nice if the docstring for var mention that it behaves differently than Clojure vars.

Show
Brian Gregg added a comment - Yes, I did figure that out after a few hours of trial and error. So can the alter-meta! documentation be updated to remove mention of vars? Also, it would be nice if the docstring for var mention that it behaves differently than Clojure vars.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated: