Reputation: 18005
I am puzzled by the difference in behavior for the following expressions:
(pr (meta ^{:a 0} (list 1 2))) ;; prints nil returns nil
(pr (meta ^{:a 0} '(1 2)));; prints {:line 110, :column 20} returns nil
(pr (meta ^{:a 0} (range 1 3))) ;; prints nil returns nil
(pr (meta ^{:a 0} [1 2])) ;; prints {:a 0} returns nil
This is using clojure 1.8.0. I would welcome an explanation as to why the results differ.
Upvotes: 2
Views: 95
Reputation: 84351
Reader metadata is attached to the form that the reader returns. meta
is, in each case, called with whatever that form evaluates to at runtime. There is no necessary link between one and the other.
If you need to attach metadata to a value at runtime, you can use with-meta
to do that.
Let's have a look at what happens in each of the cases listed in the question:
(pr (meta ^{:a 0} (list 1 2)))
Reader metadata is attached to the list structure (list 1 2)
, but meta
is applied not to this list structure, but to the value it evaluates to at runtime, which will be a freshly allocated list of two items with no metadata attached.
(pr (meta ^{:a 0} '(1 2)))
Reader metadata is attached to the list structure (quote (1 2))
(the single quote character is reader shorthand for (quote …)
), but meta
is applied not to this list structure, but to the value it evaluates to at runtime, which is the (1 2)
list structure that the reader created when reading in this expression. This carries {:line … :column …}
metadata, because the Clojure reader attaches that to certain types of forms for use in error messages and such.
(pr (meta ^{:a 0} (range 1 3)))
Same as the first case above.
(pr (meta ^{:a 0} [1 2]))
This is very similar to the '(1 2)
case with the crucial difference that while non-empty lists need to be quoted if they are not to be treated as function/macro calls, vectors do not, and so the reader metadata is actually attached to the literal of interest – the vector – itself.
This is doable with a list as well:
(pr (meta ' ^{:a 0} (1 2)))
^ note the quote comes before the metadata
;; prints {:line 1, :column 14, :a 0}
NB. the explicit reader metadata map got merged into the {:line … :column …}
map that the reader adds by itself.
Upvotes: 5