leah blogs

December 2005

31dec2005 · Ruby Symbols are not Lisp symbols

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

Copyright © 2004–2022