Pavel Ganelin
Pavel Ganelin

Reputation: 314

Function symbol and local variables

The code below prints 10 as expected.

(def x 10)
(let [y 30] (eval (symbol "x")))

The code below generates an exception:

 (let [y 20] (eval (symbol "y")))
 Unable to resolve symbol: y in this context

which is expected (but confusing!). According to the documentation, symbols defined by let do not belong to any namespace and so can not be resolved through namespace mechanism.

So the question is: what should be an equivalent of function symbol for local variables.

Additionally:

I thought that Clojure compiler internally calls function symbol for each identifier to "intern" it, but as the example above shows it is not the case. Curious what the compiler is actually doing with the local identifiers. I assumed that when I enter x in REPL

 x

is is essentially processed as this:

 (deref (resolve (symbol "x")))

but again evidently it is not the case for local variables.

PS: Symbols in Clojure does not cover local variables.

Upvotes: 1

Views: 232

Answers (1)

noisesmith
noisesmith

Reputation: 20194

All input to the clojure compiler is read, to form lists, symbols, keywords, numbers, and other readable data (eg. if you use a hash map literal, the compiler will get a hash map).

For example:

user=> (eval '(let [y 20] y))
20

In this case, we give the compiler a list starting with the symbol let (which resolves to a var macro wrapping a special form).

When you ask "what should be an equivalent of function symbol for local variables", my first thought is that you are misunderstanding what the function symbol is for. The following is equivalent to my initial example:

user=> (eval (list (symbol "let") [(symbol "y") 20] (symbol "y")))
20

symbol is only incidentally useful for getting a var from a string. In fact this usage is usually a hack, and a sign you are doing something wrong. Its primary purpose is to construct input for the compiler. Writing a form that gets a binding from its lexical scope is best done by writing a function, and having the user pass in the value to be used. History shows us that implicitly using locals in the callers environment is messy and error prone, and it is not a feature that Clojure explicitly supports (though there are definitely hacks that will work, which will be based on implementation details that are not guaranteed to behave properly the next release of the language).

Upvotes: 1

Related Questions