I saw this question already, but it doesn’t explain what I am wondering about.
When I first came to Clojure from Common Lisp, I was puzzled why it treats symbols and keywords as separate types, but later I figured it out, and now I think it is a wonderful idea. Now I am trying to puzzle out why symbols and vars are separate objects.
As far I know, Common Lisp implementations generally represent a “symbol” using a structure which has 1) a string for the name, 2) a pointer to the symbol’s value when evaluated in function call position, 3) a pointer to its value when evaluated outside call position, and 4) property list, etc.
Ignoring the Lisp-1/Lisp-2 distinction, the fact remains that in CL, a “symbol” object points directly to its value. In other words, CL combines what Clojure calls a “symbol” and a “var” in a single object.
In Clojure, to evaluate a symbol, first the corresponding var must be looked up, then the var must be dereferenced. Why does Clojure work this way? What benefit could there possibly be from such a design? I understand that vars have certain special properties (they can be private, or const, or dynamic…), but couldn’t those properties simply be applied to the symbol itself?
After giving this question a lot of thought, I can think of several reasons to differentiate between symbols and vars, or as Omri well put it, to use “two levels of indirection for mapping symbols to their underlying values”. I will save the best one for last…
1: By separating the concepts of “a variable” and “an identifier which can refer to a variable”, Clojure makes things a bit cleaner conceptually. In CL, when the reader sees
a, it returns a symbol object which carries pointers to top-level bindings, even ifais locally bound in the current scope. (In which case the evaluator will not make use of those top-level bindings.) In Clojure, a symbol is just an identifier, nothing more.This connects to the point some posters made, that symbols can also refer to Java classes in Clojure. If symbols carried bindings with them, those bindings could just be ignored in contexts where the symbol refers to a Java class, but it would be messy conceptually.
2: In some cases, people might want to use symbols as map keys and such. If symbols were mutable objects (as they are in CL), they wouldn’t fit well with Clojure’s immutable data structures.
3: In (probably rare) cases where symbols are used as map keys, etc., and perhaps even returned by an API, the equality semantics of Clojure’s symbols are more intuitive than CL’s symbols. (See @amalloy’s answer.)
4: Since Clojure emphasizes functional programming, a lot of work is done using higher-order functions like
partial,comp,juxt, and so on. Even if you’re not using these, you may still take functions as arguments to your own functions, etc.Now, when you pass
my-functo a higher-order function, it does not retain any reference to the variable which is called “my-func”. It just captures the value as it is right now. If you redefinemy-funclater, the change will not “propagate” to other entities which were defined using the value ofmy-func.Even in such situations, by using
#'my-func, you can explicitly request that the current value ofmy-funcshould be looked up every time the derived function is called. (Presumably at the cost of a small performance hit.)In CL or Scheme, if I needed this kind of indirection, I can imagine storing a function object in a cons or vector or struct, and retrieving it from there every time it was to be called. Actually, any time I needed a “mutable reference” object which could be shared between different parts of the code, I could just use a cons or other mutable structure. But in Clojure, lists/vectors/etc. are all immutable, so you need some way to refer explicitly to “something which is mutable”.