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