Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I dynamically find metadata for a Clojure function?

Say I have the following code:

(defn ^{:graph-title "Function 1"} func-1
  [x]
  (do-something-with x))

(defn get-graph-title 
  [func]
  (str
    ((meta func) :graph-title))) 

I expect this to return "Function 1", but it returns nil. I think this stems from the following difference, which I don't totally comprehend:

(meta func-1)
=>  {:ns some-ns-info, :name func-1}
(meta #'func-1)
=>  {:ns some-ns-info, :name func-1, :graph-title "Function 1"}

Can someone explain this to me?

like image 944
funkymunky Avatar asked Apr 08 '11 08:04

funkymunky


2 Answers

There's metadata on the function func-1, metadata on the Var #'func-1, and metadata on the symbol 'func-1. The Clojure reader macro ^ adds metadata to the symbol, at read time. The defn macro copies metadata from the symbol to the Var, at compile time.

Prior to Clojure 1.2, functions did not support metadata. In Clojure 1.2, they do, and defn also copies some standard Var metadata to the function:

Clojure 1.2.0
user=> (defn ^{:foo :bar} func-1 [] nil) 
#'user/func-1
user=> (meta func-1)
{:ns #<Namespace user>, :name func-1}
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...

However, in current Clojure 1.3 snapshots, defn does not copy any metadata to the function:

Clojure 1.3.0-master-SNAPSHOT
user=> (defn ^{:foo :bar} func-1 [] nil) 
#'user/func-1
user=> (meta func-1)
nil
user=> (meta #'func-1)
{:foo :bar, :ns #<Namespace user>, :name func-1, ...

In general, if you want to get at the metadata of a definition, you want metadata on the Var.

like image 174
Stuart Sierra Avatar answered Oct 04 '22 01:10

Stuart Sierra


The metadata is attached to the var, not to the function.

Thus, to get the graph title, you have to get the entry :graph-title from the meta of the var. How do you like your macros ?

(defmacro get-graph-title
  [func]
  `(:graph-title (meta (var ~func))))

(get-graph-title func-1)
=> "Function 1"
like image 32
Leonel Avatar answered Oct 04 '22 02:10

Leonel