On Jan 6, 2006, at 7:21, Jim W. wrote:
Dave H. wrote:
A variable is a box.
Hmmm … see http://onestepback.org/index.cgi/Tech/Ruby/Shoeboxes.rdoc
for an alternate view. I think the mental model of “boxes” as
variables
doesn’t work so well for Ruby.
Oh, I definitely agree. But again, my explanation is specifically for
Ruby newbies and beginners, especially those to whom “symbols” are new
territory. But I think explaining variables containing bound references
kind of has to follow the concept of variables as containers.
Gavin used fishing line to build a referencing metaphor. I’ve usually
used colored yarn, arrows, or maybe laser pointers on little tripods
when I’m trying to work it out in my head. ![]()
Reading Gavin’s post and Jim’s blog article dropped a new metaphor into
my head, one that, the more I test it out, the more I like it.
Assume that all your Objects are stored by Ruby in something resembling
an old post office mailbox room. Hundreds and hundreds of mailboxes,
all numbered, each with a key in the lock, waiting to be used. Ruby
stores strings and numbers and other Objects in these mailboxes. An
Object cannot exist unless it’s in a box. Now, I think that Ruby
might let you access these containers by number. I know C will. But why
would you want to do that? Extremely confusing and inflexible.
myName = "Dave"
And with that, Ruby builds a String, puts it in some mailbox, and hands
me a key with a tag that says “myName” on it. (The keychain tag, by the
way, is a classy metal tag with the writing engraved on it, not one of
those cheap plastic doodads with the paper you can slip out and write
on.)
currentUser = myName
Ruby makes a key tag with “currentUser” on it, duplicates the myName
key, and puts it on the “currentUser” keychain.
coolName = String.new(myName)
Ruby makes a new String just like the old one, puts it in a different
box, and puts the new different key on a chain with the tag “coolName.”
currentUser.replace("Sam")
Since “replace” replaces the contents of the String Object, Ruby takes
the key on currentUser, opens the box, takes out the String inside,
changes its contents to “Sam”, and puts it back. Obviously, if I now
print myName
I’m going to get “Sam” because that’s what’s in that box now: a String
containing the characters “Sam”.
population = 486
I have a key with a tag that says “population” that opens a box
containing a FixNum(I think?) that contains the number 483.
parkingSpaces = Array.new(40)
I have a keychain labeled “parkingSpaces.” In the corresponding box is
a board with a bunch of nails numbered 0 through 39. The nails are
empty.
parkingSpaces[3] = "VP Operations"
Now nail #3 has a key on it to a box that contains a String that
contains “VP Operations.”
The difference between an Array and a Hash is, with an Array, the nails
are numbered, but you just hang plain keys on them, keys with no tags
attached. With a Hash, you have a bunch of nails (or maybe it’s just a
bin) that are NOT numbered, but the keys all have tags.
Ruby knows which key opens which box because the keys have their box
number stamped on them.
myName.object_id
But why would I care (most of the time) what box number my information
is in, when Ruby is so willing to go get my mail and bring it back for
me? ![]()
TheAnswer = 42
Constants are like the kind of key chains you see for the bathroom at a
gas station or something. The keychain is extra big (that big Capital
Letter in the front that won’t fit in your pocket), and once you put
the key on, you can’t change it. You still get to decide what’s written
on the tag, and you can put all sorts of things in the mailbox.
[As I started to write this next section, I realized that how this all
works is still very unclear to me. Let’s see if I’ve figured it out . .
.]
sillyNum = population + 14 / "5".to_i
Ruby make a new keychain tagged “sillyNum.” There isn’t a key on this
yet. That’s what “nil” is; a keychain without a key.
Ruby takes my “population” keychain and opens that mailbox. She reaches
in to activate the enclosed FixNum’s plus method, which extends a
little chute labeled “put number here.”
The next thing on that line, the number 14, is a Literal. The Pickaxe
book isn’t really telling me exactly what happens here, but by playing
around in irb, the metaphor that seems to let me correctly predict
behavior is that Ruby manufactures a brand-new FixNum on the spot with
a 14 inside. Objects can’t exist outside boxes, but I have no idea if
she extracts the value 14 from her new FixNum or if she whispers her
new FixNum’s box number into the ear of the FixNum inside the first
box, but somehow the plus gets whatever it wanted. It spits out a new
FixNum object that contains the value 500.
I think that Ruby puts this in a box and puts the key for this box on
the sillyNum keychain.
Now she activates the divide method on the new Fixnum, and another
“put number here” chute opens.
Finally, she constructs a String object that contains the character
“5”, and turns on the to_i method on the String, which pops out a
FixNum object containing the value 5? The FixNum 5 gets dropped into
the “put number here” chute, and the value of the sillyNum FixNum
becomes 100? Or maybe it also makes a new FixNum with a value of 500.
The keychain for the box containing the “5” String is thrown away. If
another new FixNum was created, then Ruby also takes the key for the
500 FixNum off the sillyNum keychain and throws the key away. She
puts the key for the 100 FixNum on the keychain instead. I’m not sure
which, but the end result is effectively the same.
Of course, if she keeps putting things in boxes then throwing away the
keys, pretty soon there are a lot of Objects in boxes taking up space.
Ruby can always make new keys, but if there’s no keychain with that key
available, then the mailbox’s contents are inaccessible to the
programmer. When Ruby has a bit of spare time, or when too many of her
mailboxes have old Objects but no keys, she goes through and empties
out all the obsolete Objects, so she can reuse the mailboxes later.
This is called “garbage collection.”
A Symbol is kind of like a Constant, except the only thing that the
mailbox can contain is a Symbol. A Symbol is kind of like a String
encased in acrylic. Also, Ruby engraves the key tag with exactly what’s
inside the plastic. As a bonus, Symbols gets a “secret numeric
identity” engraved on the bottom. (It’s not the mailbox number.)
Symbols have almost none of the fancy accessories that come with
Strings. About all you can do with them is get a String containing the
name/contents of the Symbol, or get an Integer that contains the
Symbol’s “secret numeric identity.”
They differ from Strings in another way.
print "Dave".object_id
print "Dave".object_id
print "Dave".object_id
results in something more or less like
3945266
6941506
2937746
but
print :Dave.object_id
print :Dave.object_id
print :Dave.object_id
looks more like
8873230
8873230
8873230
That’s because, unlike literals, Ruby doesn’t throw away Symbol keys.
Every “Dave” results in a new String in a new box, and unless you
assign it to a variable (aka have Ruby put it on a keychain with a
tag), she throws the key away. But with a Symbol, Ruby always makes
the tag for the keychain when she makes the Symbol.
OK, that’s enough of that. No metaphor is perfect, but duplicating keys
seems to work quite well across a remarkable amount of territory. So
what did I get functionally wrong (it doesn’t really work quite like
that), and more importantly, what did I get effectively wrong (it
doesn’t even appear to work like that). ![]()