I came upon a weird behaviour of Clojure. Weird as far as I understand
what is going on with metadata. Maybe not very far.
I understand that the reader macro #^ associates metadata with a form,
for use by macros or the compiler as illustrated below.
user=> (defmacro m [form] `(println (meta (quote ~form))))
#'user/m
user=> (m #^{:foo "bar"} '(1 2 3))
{:line 7, :foo bar}
nil
user=> (m #^{:foo "bar"} x)
{:foo bar}
nil
I think using a macro like m is the only way to get the metadata
associated with the symbol because symbols are different everytime we
construct one, even if their spelling is the same. That explains why
(defn ff [#^Integer x] (println (meta 'x)) x) fails to display the
metadata associated with formal argument x.
But when I define a function with defn augmenting the definition with
metadata, I observe two things I don't understand. I will comment on
the code below to illustrate my problem.
mac:clojure ludo$ clj
Clojure 1.2.0-master-SNAPSHOT
user=> (defn #^{:doc "doubles argument" :tag Integer} f [#^Integer x]
(* x 2))
#'user/f
user=> (meta f)
{:ns #<Namespace user>, :name f}
user=> (defn #^{:doc "doubles argument" :tag Integer} f [#^Integer x]
(* x 2))
#'user/f
user=> (meta f)
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line
1, :arglists ([x]), :doc "doubles argument", :tag java.lang.Integer}
user=> (meta #'f)
{:ns #<Namespace user>, :name f, :file "NO_SOURCE_PATH", :line
3, :arglists ([x]), :doc "doubles argument", :tag java.lang.Integer}
The first defn defines a fuction called f with metadata provided by
the reader for the symbol f and the symbol x. Thus the special form
def (hidden behind the macro defn) takes the metadata and associates
it with the var #'f.
1) When I call (meta f), I get something. I thought there can't be any
metadata on a function value. But I see :ns and :name in the map.
2) If a redefine f with the same call to defn, I get full metadata on
the value of f as well as #'f. As meta is an ordinary function, the
argument f gets evaluated, producing a function value and then I
retrieve the metadata associated with the value and get the whole
stuff as if I called it on #'f.
Point 1 is weird but point 2 is even weirder.
I would be thankful if anyone could provide insights on this problem.
Ludovic Kuty
This would appear to support the above:
user> (def #^{:foo "bar"} x 5)
#'user/x
user> (meta #'x)
{:ns #<Namespace user>, :name x, :file "NO_SOURCE_FILE", :line 1, :foo "bar"}
user> (defn x [] 5)
#'user/x
user> (x)
5
user> (meta x)
{:ns #<Namespace user>, :name x, :file "NO_SOURCE_FILE", :line 1, :foo "bar"}
Sincerely,
Michał
user> (meta #'x)
{:ns #<Namespace user>, :name x, :file "NO_SOURCE_FILE", :line 1,
:arglists ([])}
Thus there's a sort of an off-by-one error in that the function
created by defn gets the metadata which was attached to its Var
*before* the defn form was evaluated (which will be the metadata of a
newborn Var if the defn form is the first one to have it constructed),
whereas the Var is subsequently given the correct metadata for the
function. Ouch. :-)
Sincerely,
Michał
I completely forgot about the first point... Metadata on functions has
been introduced some time ago, can't seem to remember when exactly.
Also, I've researched the second issue a little bit more and will post
my findings in a second while changing the title of this thread in
hope of bringing extra attention to what I think may be a bug in
Compiler.java...
Sincerely,
Michał
I saw a post where Rich Hickey mentionned that he was planning to add
metadata to functions but I didn't know it was already done from what
I saw on the net.
On Feb 8, 2:54 am, Michał Marczyk <michal.marc...@gmail.com> wrote: