Paul Graham offers this excellent explanation for the symbol type:
"Symbols are effectively pointers to strings stored in a hash table.
So you can test equality by comparing a pointer, instead of comparing
each character." [1]
Of course, he's talking about symbols in Lisp, but what he says
applies equally well to Ruby and Smalltalk.
I find this a little too implementation-centric a description.
The key aspect of symbols is that two symbols are identical if they are equal.
The fact that there may (or may not be) a hash table used to ensure
this is irelevant.
And that description really misses the boat as far as Lisp is
concerned. Lisp symbols aren't strings, they are really names to which
three (separate) things can be bound, a value (which can be any Lisp
object), a function, and a property list. Actually the name is also
one of the slots in a symbol.
Note that in Lisp the value of a Symbol is separate from it's name,
and two Symbols can have the same value, they just can't have the same
name.
So in Lisp a symbol is more like an entry in the table of global names.
Symbols in Ruby and Smalltalk are more alike than Symbols in Lisp.
Smalltalk and Ruby symbols have unique 'values' which are also their 'names'.
Most Smalltalk implementations make Symbol a subclass of String,
although I'm pretty sure that we didn't require this when we wrote the
X3J20 ANSI Smalltalk spec (We didn't require much if any particular
inheritance hierarchy). Ruby does not treat Symbols as Strings,
although one can obtain an instance of either from an instance of the
other.
Not long ago Matz experimented with the idea of making Symbol a
subclass of String in 1.9, but this appears to have been dropped in
more recent versions.