Seq forms with preceding #^metadata lose the metadata

238 views
Skip to first unread message

Kei Suzuki

unread,
Dec 2, 2008, 4:30:34 AM12/2/08
to Clojure
Hi,

Whenever a seq form is preceded by #^metadata, the metadata is ignored
or only {:line n} is associated with.

For example, these return the metadata as expected:

(meta (with-meta '(1) {:v 1}))
(meta (with-meta (quote (1)) {:v 1}))
(meta (with-meta (list 1) {:v 1}))
(meta (with-meta (vector 1) {:v 1}))
(meta (with-meta (hash-map :a 1) {:v 1}))
(meta (with-meta (set [1]) {:v 1}))

But none of these equivalents work and either nil or {:line n} is
returned:

(meta #^{:v 1} '(1))
(meta #^{:v 1} (quote (1)))
(meta #^{:v 1} (list 1))
(meta #^{:v 1} (vector 1))
(meta #^{:v 1} (hash-map :a 1))
(meta #^{:v 1} (set [1]))

However, these work (because what's following is a non-seq form):

(meta #^{:v 1} [1])
(meta #^{:v 1} {:a 1})
(meta #^{:v 1} #{1})

Looking at the Clojure source code, it looks like
LispReader.MetaReader does associate the metadata to the seq form but
it's ignored when the seq form is analyzed by Compiler.analyzeSeq.

Is this by design?

Meikel Brandmeyer

unread,
Dec 2, 2008, 4:41:59 AM12/2/08
to Clojure
Hi,

On 2 Dez., 10:30, Kei Suzuki <ksd...@gmail.com> wrote:
> (meta #^{:v 1} (vector 1))
>
> Is this by design?

I think you are right. The metadata is assigned to
the list (vector 1). Then the function vector is executed
and you get the vector [1], but the metadata is "lost".
So one could argue, the metadata should be transferred.

However, how do you want to do this consistently?
Consider (meta #^{:v 1} (fn [] 1)). The metadata is
assigned to the list (fn ...). But why should it transfer
the metadata to the return value of the function? And
indeed this is not possible, because it's a number.

Should vector, set and friends behave differently?

I think the point about *reader* macros is, that they
happen at *read* time. However, the call to vector
happens at run-time. So in that case one has to
use with-meta.

One really has to be aware of the different times
when things happen:
- reader macros => read time
- macros => compile time
- functions => run-time

Sincerely
Meikel

Rich Hickey

unread,
Dec 2, 2008, 9:59:50 AM12/2/08
to Clojure
First and most important:

#^ is not sugar for with-meta. It does not expand into a call to with-
meta. They are not equivalent.

#^ is a way to place metadata on the data objects read by the reader.
Once read by the reader, the compiler can utilize metadata on the
forms. Currently the primary use is to convey type hints. Macros can
interpret metadata on forms they are passed for various purposes. This
is all about code-as-data, not a runtime thing.

Since a list is interpreted by the compiler as a call, any metadata on
the list is searched for type hints. There is no other meaning for
metadata on a list as far as the compiler is concerned. Ditto metadata
on symbols.

Since vector and map literals are interpreted by the compiler as
evaluated data, it evaluates any metadata on the literal to become
metadata on the value:

(set! *print-meta* true)

(quote #^{:a (+ 1 2)} [1 2 (+ 3 4)])
=> #^{:a #^{:line 17} (+ 1 2)} [1 2 #^{:line 17} (+ 3 4)] ;what was
read, vector + meta

#^{:a (+ 1 2)} [1 2 (+ 3 4)]
=> #^{:a 3} [1 2 7] ;evaluated vector + meta

Metadata on a seq form is not ignored:

(set! *print-meta* false)
(set! *warn-on-reflection* true)

(def x "foo")

(.length (identity x))
=> Reflection warning, line: 26 - reference to field length can't be
resolved.
=> 3

=> (.length #^String (identity x))
=> 3

So #^ allows the reader to read data with metadata on it.
Interpretation of forms that have metadata is up to the compiler.

Bottom line:

#^ is not sugar for with-meta. It does not expand into a call to with-
meta.

Rich


Kei Suzuki

unread,
Dec 3, 2008, 2:25:51 AM12/3/08
to Clojure
Hi Meikel, Rich,

Thank you for your clarification.

Now I understand the difference between #^ and with-meta and I can see
#^metadata on a seq form is intact at compile time (and it can be
passed down to runtime) so that now I know I was wrong to say like the
topic.

Thanks again.

--
Kei
Reply all
Reply to author
Forward
0 new messages