Updated:
The previous version of my answer was not very robust. This seems like a simpler and more proper way of doing it, stolen from clojure.contrib.def
:
(defmacro defn-plus [name & syms]
`(defn ~(vary-meta name assoc :some-key :some-value) ~@syms))
user> (defn-plus ^Integer f "Docstring goes here" [x] (inc x))
#'user/f
user> (meta #'f)
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line 1, :arglists ([x]), :doc "Docstring goes here", :some-key :some-value, :tag java.lang.Integer}
#^{}
and with-meta
are not the same thing. For an explanation of the difference between them, see Rich's discussion on the Clojure mailing list. It's all a bit confusing and it's come up a bunch of times on the mailing list; see also here for example.
Note that def
is a special form and it handles metadata a bit oddly compared with some other parts of the language. It sets the metadata of the var
you're def
fing to the metadata of the symbol that names the var; that's the only reason the above works, I think. See the DefExpr
class in Compiler.java
in the Clojure source if you want to see the guts of it all.
Finally, page 216 of Programming Clojure says:
You should generally avoid reader macros in macro expansions, since reader macros are evaluated at read time, before macro expansion begins.