Nested Arrays in Method Definitions--a puzzle

Hello there Ruby-minded people!

 I am writing because I am somewhat stumped by why the following

discrepency occurs; having defined the following:

class Warfare
def haves
x = [1]
y = []
y << x
x = [2] # (compare this)
def havenots
x = [1]
y = []
y << x
x[0] = 2 # (to this)

I get this in irb:

load ‘snah.rb’
=> true

a =
=> #Warfare:0x33a93c

=> [[1]]

=> [[2]]

Why does meddling with the innards of the “x” have retroactive
repercussions, whereas redefining it outright does not?

Any insight would be greatly appreciated.


On Tue, Aug 19, 2008 at 4:16 PM, Jonah Bloch-Johnson
[email protected] wrote:

repercussions, whereas redefining it outright does not?
When you say ‘x = [2]’ you aren’t redefining the object x, you are
taking the variable ‘x’ and binding it to a new object. When you say y
<< x, you are inserting the object that x was pointing to at that
moment into y, not the variable x. Think of a variable as an alias for
an object - what is actually passed around are the objects themselves,
but you can refer to them by any of their current aliases.


Many many many thanks, Adam and Martin! I do think this clears it up.

Quoting A. Shelly [email protected]:

On 8/19/08, Jonah Bloch-Johnson [email protected] wrote:

I am writing because I am somewhat stumped by why the following discrepency occurs…

Variables and Array entries hold references to objects.

irb(main):001:0> x=[1]
=> [1]
irb(main):002:0> x.object_id
=> 20774910

irb(main):003:0> y=[];y<<x
=> [[1]]
irb(main):004:0> y[0].object_id
=> 20774910 #the same object that x referrs to

irb(main):005:0> x=[2]
=> [2]
irb(main):006:0> x.object_id
=> 21222360 #now x refers to the newly created array

irb(main):008:0> y
=> [[1]]
irb(main):007:0> y[0].object_id
=> 20774910 #but y still holds a reference to the old one.

irb(main):009:0> y=[x]
=> [[2]]
irb(main):010:0> y[0].object_id
=> 21222360 #y[0] is now a reference to the same Array as x

irb(main):011:0> x[0]=4
=> 4
irb(main):013:0> y
=> [[4]] #so changes to the content of that Array are visible
through y’s reference.

hope this helps,

   x = [1]

[1] is an Array object, x is a variable referring to that array

   y = []

y referrs to a 2nd Array

   y << x

And now that array contains a reference to

   x = [2] # (compare this)

Here you are creating an array, labeling it ‘x’, and storing a
reference to it in the array labeled y. Then you reassign the ‘x’
label to yet another array (the one containing 2).