syntax | since v0.0-1853 | in clojure | Edit |
Attach metadata to the following symbol or collection. Use a map to specify the metadata, or use shorthand:
^:foo
=> ^{:foo true}
^"foo"
=> ^{:tag "foo"}
^foo
=> ^{:tag foo}
Attach metadata to a collection:
^:foo [1 2 3]
;;=> [1 2 3]
View the resulting metadata:
(meta ^:foo [1 2 3])
;;=> {:foo true}
(meta ^{:foo "bar"} [1 2 3])
;;=> {:foo "bar"}
(meta ^"foo" [1 2 3])
;;=> {:tag "foo"}
(def foo 1)
(meta ^foo [1 2 3])
;;=> {:tag 1}
Chain metadata:
(meta ^:foo ^"foo" [1 2 3])
;;=> {:foo true, :tag "foo"}
Generally, metadata maps used purely by the compiler are not evaluated and should be read literally:
(defn foo [^js x] ;; ^js => ^{:tag js} (literal map not evaluated)
^js (.-bar x)) ;; ^js => ^{:tag js} (literal map not evaluated)
But here’s one exception— metadata maps are evaluated when placed behind literal collections created at runtime:
(def foo (+ 1 2 3))
(meta ^foo {}) ;;=> {:tag 6} not {:tag foo}
(meta ^{:foo (+ 1 2 3)} []) ;;=> {:foo 6} not {:foo (+ 1 2 3)}
(defn- read-meta
[rdr _ opts pending-forms]
(log-source rdr
(let [[line column] (starting-line-col-info rdr)
m (desugar-meta (read* rdr true nil opts pending-forms))]
(when-not (map? m)
(err/throw-bad-metadata rdr m))
(let [o (read* rdr true nil opts pending-forms)]
(if (instance? IMeta o)
(let [m (if (and line (seq? o))
(assoc m :line line :column column)
m)]
(if (instance? IObj o)
(with-meta o (merge (meta o) m))
(reset-meta! o m)))
(err/throw-bad-metadata-target rdr o))))))
(defn- macros [ch]
(case ch
\" read-string*
\: read-keyword
\; read-comment
\' (wrapping-reader 'quote)
\@ (wrapping-reader 'clojure.core/deref)
\^ read-meta
\` read-syntax-quote ;;(wrapping-reader 'syntax-quote)
\~ read-unquote
\( read-list
\) read-unmatched-delimiter
\[ read-vector
\] read-unmatched-delimiter
\{ read-map
\} read-unmatched-delimiter
\\ read-char*
\% read-arg
\# read-dispatch
nil))