Hi --

On Mon, 5 Dec 2005 gwtmp01 / mac.com wrote:

> When I was first learning Ruby, symbols were a bit of a mystery.
> I understand them now, and in hindsight, I don't really understand
> why they were so confusing.  In teaching other people about Ruby and
> in reading ruby-talk it is quite clear that symbols are an early
> stumbling block for learning Ruby.  I'd take an educated guess that
> people learning Rails (or any other Ruby framework) struggle with
> trying to understand if symbols are a magic feature of the framework
> or the language or something else.
>
> My question to the list is, why?  What is it about Symbols that
> creates such confusion?  I'm getting ready to prepare a two-hour
> "Intro to Ruby" seminar and I'd like to find an approach to Symbols
> that cuts through the confusion.

I've seen Symbol confusion in the following forms:

1. Confusion between Symbol objects and symbols in the sense of
identifiers in a Ruby program.  This code:

  x = 1

may result in :x being put in the symbol table, but the x in that
expression is not a Symbol object.  I don't think this distinction is
always clear to people.

2. Overuse of symbols.  This kind of thing:

  methods.each do |m| something.send(m.intern) end

is almost certainly pointless, in terms of efficiency.  I think symbols
have a kind of mystique -- as if there's something sort of sloppy or
substandard or laughably high-level about using strings where you could
use symbols.  In fact, the methods that take strings or symbols as
arguments are usually well-engineered to handle either.

3. Over-emphasis on the symbol table and its meaning.  Maybe I
under-emphasize it in my own thinking... but I've never seen any practical
reason to think of symbols in terms of a table, even if one exists
internally.  I can't call to mind any case where the data structures
involved in the interpreter's handling of symbols would make any
difference to me.  All I need to know is that symbols are immediate,
immutable, and fast.

I'm not campaigning against understanding the interpreter.  But from the
user side -- which is where we are when we use Ruby -- symbols are still
an abstraction.  When I do "send(:meth)", I'm not manipulating the symbol
table *as* a table.  The table-ness is an implementation detail.  Symbol
objects are part of Ruby.

4. Conflation of symbols and methods.  Sort of along the same lines: :meth
is no closer to the method you get when you do method(:meth) than "meth"
is.  It may be closer internally, but in practical terms, it isn't.  You
can't do: :meth += "2" and change the name of "meth" to "meth2".  The
symbol is the ending point, not the starting point.

> One thought that I've had is that Ruby's reflection capabilities expose
> the names of various internal structures (classes, methods, modules,
> constants) in a way that is quite foreign to many programmers. For
> example, in C you don't have any runtime access to the symbol table so
> you would never see a value that could be mapped to a function like
> 'printf', 'scanf', or 'main' unless the programmer took the trouble to
> construct an explicit symbol table (mapping strings to function
> pointers, for example).  An explicit table isn't much of a mystery.

To my knowledge there's no programmatic access to the underlying symbol
table in Ruby.  (Am I wrong about this?  Have I missed all the
table-manipulating fun? :-)

> When you switch to a language like Ruby, Smalltalk, and certainly the
> entire family of Lisp languages you are now in an environment where the
> data structures of the language runtime are exposed to the programmer.
> For a while, the novice will struggle because their mental model of
> a runtime environment just doesn't match their new reality and symbols
> just happen to be the bridge between the two worlds.  One of the first
> features of Ruby that many people learn are the 'attr*' methods.  Right
> off the bat, the novice is exposed to the mappings from strings to
> symbols to methods.

Again, I think that from the programmer's perspective, you can map from
strings to methods just as easily:

  attr_reader :a
  attr_reader "a"
  attr_reader :a.to_s
  attr_reader "a".to_sym

Obviously the first one is the common case, and the first two are the only
useful ones.  But conceptually, I think of strings and symbols, in such
cases, as equidistant from the underlying method -- except for the hint
that symbols are faster.


David
__
David A. Black
dblack / wobblini.net

"Ruby for Rails", forthcoming from Manning Publications, April 2006!