0

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.

1 Answer 1

6

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
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your answer. But then how do I get the content of the var ? (println my-var) outputs nil.
Correction sorry, it outputs sample-data1 , etc. Which is what I asked, but now I don't get why you are using meta :name. Also, how can you still access the content (ie {:data 1}) ?
i just updated my answer on why I use meta :name. You get the value pointed by a var by using dereference deref or @ to that var (there's a example in my answer above).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.