nha
nha

Reputation: 18005

how to get the name string from a variable or function?

I would like to get the name of a variable as a string in Clojure. However, unlike in this question, I would get the name of the original binding (not sure if the terminology is correct, so please see my example below).

(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})


(doseq
    [my-var [sample-data1 sample-data2 sample-data3]]
  (println (name 'my-var)))

In this case, instead of printing

my-var
my-var
my-var

I would like to have :

sample-data1
sample-data2
sample-data3

How do I do that in Clojure ?

Note : This is probably not the prettiest thing to do in a real app. But my question is about if this is this possible.

To clarify : this is for prototyping purposes. In this specific case instead of printing I am filling a (postgres) database with fake data that I write by hand in variables, and I'd like to track where my variable end up without writing too much code.

Upvotes: 0

Views: 510

Answers (1)

mavbozo
mavbozo

Reputation: 1261

def creates a var with the same name as the name of the symbol supplied as def first parameter. Var in clojure differs from what we usually meant by variable whereas a variable usually can be visualized as a box that contains a value and a var is something that points to a value.

From your example, (here, I am in user namespace)

user> (def sample-data1 {:data 1})
#'user/sample-data1

clojure creates a #'user/sample-data1 var in user namespace which points to {:data 1} value. You can get the value back from that newly create var by deref-ing it using deref or @ shorthand.

user> (deref #'user/sample-data1)
{:data 1}
user> @#'user/sample-data1
{:data 1}

or if you evaluate a symbol, clojure looks up for a var in the current namespace and returns the value pointed by that var.

user> sample-data1
{:data 1}

you can get a var from a symbol by using var for #' shorthand.

user> (var sample-data1)
#'user/sample-data1
user> #'sample-data1
#'user/sample-data1

So, you want the name of the var. The name of the var is contained inside the var's meta data which can be accessed using meta applied to a var.

user> (meta #'sample-data1)
{:line 1, :column 1, :file "/tmp/form-init3246148490151701909.clj",
 :name sample-data1, :ns #object[clojure.lang.Namespace 0x39ba2c26 "user"]}

Above, you can see that the name of the var is located by :name key.

so, you can get the name of a var from its metadata.

user=> (:name (meta #'sample-data1))
sample-data1

I prefer not to have too many nested parenthesis, so I use thread-first macro ->

user=> (-> #'sample-data1 meta :name)
sample-data1

the answer

So back to your question, you need the sample-data[1-3] vars and their metadata to get their name.

(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})

(doseq
    [my-var [#'sample-data1 (var sample-data2) #'sample-data3]] 
  (println (-> my-var meta :name)))

and the result is

sample-data1
sample-data2
sample-data3
nil

Upvotes: 6

Related Questions