|
This is a reposting of an article on RubyTalk from about a year ago.
I’m posting it here in anticipation of a related posting later.
When I was first learning about programming (mumble mumble) years ago,
variables were explained to me as shoeboxes. A variable name denoted a
location in memory (a shoebox) which can hold things. You put values into
the shoebox and they stay in there until you put something else in there.
Each shoebox is exactly the right size to hold the type of data you put
into it. Integers fit in int-sized shoeboxes and floating point numbers fit
in float-sized shoeboxes. Pointers can be added to this model by
envisioning labels (addresses) for each shoebox and storing a shoebox label
in another shoebox.[1]
Assignment is the act of copying a new value into one of your shoeboxes.
This model works really well for understanding FORTRAN (the language I was
learning at the time) and Algol, and reasonable well for C and C++.
HOWEVER, this is exactly the wrong way to think about Ruby variables.
Consider the code …
a = b = "Hello"
The shoebox model encourages us to think that the string is in the
‘a’ shoebox and another string is in the ‘b’
shoebox. Therefore we are surprised when modifying a changes b. To explain
this within the shoebox model, we resort to talking about references and
how the shoeboxes ‘a’ and ‘b’ don’t actually
hold the string object, but hold a reference to it.
All of this is perfectly correct, but I believe there is a better model to
use for Ruby variables.
In Ruby, the variable ‘a’ does not represent a shoebox that can
store things. Instead, it represents an association between a name and an
object. We call this association a "binding". Executing the code
…
a = "Hello"
binds the name ‘a’ to the string object "Hello".
References to ‘a’ after the assignment will lookup the name
‘a’ in a dictionary of bindings and will find the object
currently associated with ‘a’. We no longer need think of
variables as shoeboxes containing objects, but as names associated (bound)
to objects.[2]
I see a number of advantages to this point of view.
- The distinction between immediate values (like Fixnum) and reference values
(most everything else) becomes invisible.
- Multiple assignment statements (like ‘a = b =
"Hello"’) is explained in terms of binding the names
‘a’ and ‘b’ to the same object. No need to talk
about pointers or references.
- Assignment becomes an operation that is outside an object. Objects
don’t care what names they are bound to. Therefore binding is not an
operation on an object and won’t ever be a method on an object. This
helps explain why "+=" is not a method and why "++"
can’t be implemented as a method.
I found that adopting this view has helped me understand Ruby better. I
hope it helps you as well. Comments and feedback are encouraged.
Footnotes
- I used this technique to explain pointers when I taught a class in C,
except I used styrofoam cups with labels instead of shoeboxes. I would
write on yellow postit notes and drop them into the cups (variables). Each
cup had a label, so to represent a pointer I would write another
cup’s label on a postit and put it in a cup representing a pointer
variable. It was actually a rather effective in demonstration.
- Variables as name bindings is not unique to Ruby. I first encountered the
concept when learning Lisp (what I learned after studying FORTRAN).
I’ve also read threads in the Python newgroup where someone was
offering a similar explaination of variable binding for Python. I’m
sure there are many other languages where binding is a better model than
shoeboxes.
|