With all the rage for reasons whatsoever about Ruby and its Symbols, people often start to compare Ruby symbols with Lisp symbols. Don’t do that, it’s just wrong.
Ruby symbols are not Lisp symbols!
There are at least six important differences:
For Lisp symbols, the Common Lisp Hyperspec says (in this post, Lisp is considered to be Common Lisp):
Symbols are used for their object identity to name various entities in Common Lisp, including (but not limited to) linguistic entities such as variables and functions.
Symbols can be collected together into packages. A symbol is said to be interned in a package if it is accessible in that package; the same symbol can be interned in more than one package. If a symbol is not interned in any package, it is called uninterned.
About Ruby symbols, ri
says:
Symbol objects represent names and some strings inside the Ruby interpreter. […] The same Symbol object will be created for a given name or string for the duration of a program’s execution, regardless of the context or meaning of that name.
This is the first imporant difference: Ruby symbols are globally
unique, Lisp symbols can exist in several packages. This means that
there can be symbols in Lisp which have the same name but are
different: FOO
and FOO
will always be the same, but a symbol
FOO
given in package A to a function in package B will not be equal
to FOO
there. This can easily confuse newbies.
Second difference: Lisp symbols can be uninterned, whereas Ruby symbols only exist when they are interned. (An exercise to the Ruby curious: Find out how to check if a symbol with given name exists, without interning it. Answer below.)
Third difference: Lisp symbols carry data, Ruby symbols only identify.
A certain Lisp symbol has two slots, a value cell and a function cell.
Since Common Lisp is a Lisp-2, a symbol therefore can “be” a
variable and a function at the same time. Ruby symbols aren’t
anything, but they can be used to lookup methods (but not local
variables, despite Ruby also being a Lisp-2… and for instance variables,
don’t forget the @
).
Fourth difference: Lisp symbols have a property list, Ruby symbols don’t (but you could add that). Imagine a Lisp property list like instance variables in Ruby. Property lists often are used to attach data to symbols (this was used for the first object-oriented programming styles, a.k.a. “flavours” in Lisp, for example).
Fifth difference: Lisp symbols can get garbage-collected if they are
unbound, Ruby symbols stay alive forever. This can be considered an
implementation detail but has to be kept in mind if you intern
a lot
in long running processes. (Don’t!)
Sixth difference: Lisp symbols are upcased automatically by default,
Ruby symbols are created as specified. Basically, foo
and FOO
is
the same in Lisp, but :foo
and :FOO
aren’t in Ruby. To create
something like :foo
in Lisp, you’d need to write |foo|
.
These differences make clear that Lisp symbols are rather different to
Ruby symbols, but there is one “exception”, the Lisp symbols of
package KEYWORD. Now, guess how these Lisp symbols are
created… exactly: with a leading colon. The Lisp symbol :foo
is a symbol called “FOO” in the package “KEYWORD”. Therefore, the
Lisp symbol created given by :foo
always is the same as :foo
.
Keywords are mainly used for keyword parameters (cf. Rails), where the
calling package often isn’t the definiton package.
I conclude:
Ruby symbols aren’t Lisp symbols, but Lisp keywords.
Answer to the exercise:
puts "U3ltYm9sLmFsbF9zeW1ib2xzLmFueT8geyB8c3wgcy50b19zID09IGdpdmVu
X25hbWUgfQ==\n".unpack('m*')
NP: David Gilmour—Terrapin