jayunit100
jayunit100

Reputation: 17650

Clojure : Determine if a variable is declared

How can I test wether a variable has been declared or assigned (i.e. check if "a" is defined, when I expect a program to call some code like this (def a (create-a)) ?

And related --- how does the answer to this question relate to the problem of resolving a symbol (i.e. a function) which has been declared ? Clojure: determine if a function exists

It seems like a defined variable should be checkable in the same sense that a defined function is, but I'm finding that the solution for determining if a function exists is not sufficient for determining wether a variable exists.

Some context : I'm writing unit tests for a multideveloper project, and want to make sure that the test data, and the methods in different classes have been defined. Since there is no good IDE support for clojure, it seems to me that, given its loose structure, it is good to test method names and variable names existence before testing their outputs / content.

Upvotes: 13

Views: 4116

Answers (4)

amalloy
amalloy

Reputation: 92147

Since there is no good IDE support for clojure it seems to me that, given its loose structure, it is good to test method names and variable names existence before testing their outputs / content.

This is nuts. You really want a test to say "Oops! You forgot to define foobar!" instead of just trying to run foobar and seeing Clojure's "Unable to resolve symbol" message?

What do you gain from this? You lose the stacktrace, which could be useful if, for example, the test is passed the wrong function name by some other code. Much better to know what line mis-spelled foobar than to search through your whole test namespace.

Upvotes: 1

Alex Taggart
Alex Taggart

Reputation: 7825

As others have said, resolve will return the var for a symbol if there is one defined, or nil. Further, you can check if the var has a value bound to it by using bound?.

user=> (resolve 'foo)
nil
user=> (def foo)
#'user/foo
user=> (resolve 'foo)
#'user/foo
user=> (bound? #'foo)
false
user=> (def foo 5)
#'user/foo
user=> (bound? #'foo)
true

Upvotes: 4

Paul
Paul

Reputation: 8182

One way to do this is to use ns-resolve, for example:

user=> (def a "hello a")
user=> (ns-resolve *ns* 'a)
#'user/a
user=> (ns-resolve *ns* 'b)
;nil                    ; This assumes b hasn't been defined before...

Note that if you namespace-qualify the symbol to be checked then what you pass as first argument (*ns* in the example above) doesn't matter:

user=> (ns-resolve 'user 'a)
#'user/a
user=> (ns-resolve 'other 'a)
nil
user=> (ns-resolve 'other 'user/a)
#'user/a

The resolve function mentioned by @tolitius is actually a shorthand for ns-resolve where the namespace argument always evaluates to ns, depending on the use case it might be more handy.

Upvotes: 4

tolitius
tolitius

Reputation: 22549

You can use resolve to see if the variable was bound/defined:

(resolve 'meaning)
nil

(def meaning 42)
#'user/meaning

(resolve 'meaning)
#'user/meaning

or you can boolean check it, if you need true/false:

(boolean (resolve 'meaning))
true

Upvotes: 13

Related Questions