Other questions have touched on many true aspects of symbols, but I’ll try explaining it from another angle.
Symbols are names
Unlike most programming languages, Clojure makes a distinction between things and the names of things. In most languages, if I say something like var x = 1
, then it is correct and complete to say “x is 1” or “the value of x is 1”. But in Clojure, if I say (def x 1)
, I’ve done two things: I’ve created a Var (a value-holding entity), and I’ve named it with the symbol x
. Saying “the value of x is 1” doesn’t quite tell the whole story in Clojure. A more accurate (although cumbersome) statement would be “the value of the var named by the symbol x is 1”.
Symbols themselves are just names, while vars are the value-carrying entities and don’t themselves have names. If extend the earlier example and say (def y x)
, I haven’t created a new var, I’ve just given my existing var a second name. The two symbols x
and y
are both names for the same var, which has the value of 1.
An analogy: my name is “Luke”, but that isn’t identical with me, with who I am as a person. It’s just a word. It’s not impossible that at some point I could change my name, and there are many other people that share my name. But in the context of my circle of friends (in my namespace, if you will), the word “Luke” means me. And in a fantasy Clojure-land, I could be a var carrying around a value for you.
But why?
So why this extra concept of names as distinct from variables, rather than conflating the two as most languages do?
For one thing, not all symbols are bound to vars. In local contexts, such as function arguments or let bindings, the value referred to by a symbol in your code isn’t actually a var at all – it’s just a local binding that will be optimized away and transformed to raw bytecode when it hits the compiler.
Most importantly, though, it’s part of Clojure’s “code is data” philosophy. The line of code (def x 1)
isn’t just an expression, it’s also data, specifically a list consisting of the values def
, x
, and 1
. This is very important, particularly for macros, which manipulate code as data.
But if (def x 1)
is a list, than what are the values in the list? And particularly, what are the types of those values? Obviously 1
is a number. But what about def
and x
? What is their type, when I’m manipulating them as data? The answer, of course, symbols.
And that is the main reason symbols are a distinct entity in Clojure. In some contexts, such as macros, you want to take names and manipulate them, divorced from any particular meaning or binding granted by the runtime or the compiler. And the names must be some sort of thing, and the sort of thing they are is symbols.