I'm afraid this use case is Rich's idea and not mine, but perhaps it will be of interest:
The language itself uses this feature in def
forms (and convenience macros wrapping def
, including defn
and defmacro
), because metadata attached to the symbols naming the Vars being created is transferred to the Vars themselves. It can then be used by the compiler and various tools.
One might point out that defn
& Co. optionally take an attribute map argument which gets merged into the Vars metadata, so using metadata on the symbolic name is not necessary from the user's point of view. Plain def
, however, does not, and internally defn
expands to a def
form with the metadata coming from the attribute map attached to the Var name itself. (For the sake of completeness, it is possible to modify a Var's metadata map in a separate step after its creation, but this is not what happens in defn
.)
All this is not hidden from the programmer at all, by the way. On the contrary, attaching metadata to the symbol "by hand" is in many cases more concise than using the attribute map (perhaps one could even say more idiomatic). Clojure's own standard library uses this style (and I mean post-bootstrap) -- for example, both clojure.core
and clojure.string
define Vars named replace
, but only the latter is tagged with the return value type (namely String
):
;;; clojure.core
(defn replace
...)
;;; clojure.string
(defn ^String replace
...)
^String
here is transformed to {:tag String}
, which is attached to the symbol replace
at read time and later used by the compiler (as a type hint). Other uses include marking Vars as private with ^:private
(in Clojure 1.3, ^{:private true}
in 1.2), attaching docstrings to Vars created with plain def
(the only way to do it in 1.2; 1.3 allows an extra docstring argument, but ^{:doc "..."}
is still being used) etc.
Similarly, in ClojureScript, you could have two functions named foo
only one of which should be exported (living in different namespaces, of course). In that case you'd say
(defn ^:export foo ...)
in one namespace and
(defn foo ...)
in the other; ^:export
gets translated to ^{:export true}
at read time, this gets merged into the metadata of this occurrence of the symbol foo
and then read and acted upon by the ClojureScript compiler.