I think this is due to DefExpr's eval method binding the Var to
init.eval() first and attaching the supplied metadata to the Var later
-- see Compiler.java lines 341-352. (Note the Var is always already in
place when init.eval() is called, regardless of whether it existed
prior to the evaluation of the def / defn.) Thus the init expression
supplied by defn sees the old (and wrong) metadata on the Var.
Simply switching the if(initProvided) and if(meta != null) around
seems to produce some weird error, though, and my Java-fu is
regrettably too limited for me to be able to suggest a solution. :-(
Please find below a sample interaction at the REPL illustrating the
above (quoted from my earlier answer to Ludovic Kuty).
Sincerely,
Michał
> 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"}
> user> (meta #'x)
> {:ns #<Namespace user>, :name x, :file "NO_SOURCE_FILE", :line 1,
> :arglists ([])}