Share your thoughts in the 2024 State of Clojure Survey!

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

+1 vote
in ClojureScript by
(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.

5 Answers

0 votes
by

Comment made by: baritonehands

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!
(link: iref f & args)
(set! (.-meta iref) (apply f (.-meta iref) args)))

(deftype Var (link: val sym meta)
...
IMeta
(-meta (link:
) _meta)
...

0 votes
by

Comment made by: baritonehands

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?

0 votes
by

Comment made by: thheller

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.

0 votes
by

Comment made by: baritonehands

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.

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