# Nested Arrays in Method Definitions--a puzzle

Discussion in 'Ruby' started by Jonah Bloch-Johnson, Aug 20, 2008.

1. ### Jonah Bloch-JohnsonGuest

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)
y
end
def havenots
x = [1]
y = []
y << x
x[0] = 2 # (to this)
y
end
end

I get this in irb:

=> true
>> a = Warfare.new

=> #<Warfare:0x33a93c>
>> a.haves

=> [[1]]
>> a.havenots

=> [[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.

-Jonah

Jonah Bloch-Johnson, Aug 20, 2008

2. ### Martin DeMelloGuest

On Tue, Aug 19, 2008 at 4:16 PM, Jonah Bloch-Johnson
<> wrote:
>
> def haves
> x = [1]
> y = []
> y << x
> x = [2] # (compare this)
> y
> end
>
> Why does meddling with the innards of the "x" have retroactive
> 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.

martin

Martin DeMello, Aug 20, 2008

On 8/19/08, Jonah Bloch-Johnson <> 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).

> end
> def havenots
> x = [1]
> y = []
> y << x
> x[0] = 2 # (to this)
> y
> end
> end
>
> I get this in irb:
>
> >
> > >

> >

> => true
> >
> > > a = Warfare.new
> > >

> >

> => #<Warfare:0x33a93c>
> >
> > > a.haves
> > >

> >

> => [[1]]
> >
> > > a.havenots
> > >

> >

> => [[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.
>
> -Jonah
>
>
>

4. ### Jonah Bloch-JohnsonGuest

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

> On 8/19/08, Jonah Bloch-Johnson <> wrote:
>
>> I am writing because I am somewhat stumped by why the following =20
>> discrepency occurs...

>
> Variables and Array entries hold references to objects.
>
> irb(main):001:0> x=3D[1]
> =3D> [1]
> irb(main):002:0> x.object_id
> =3D> 20774910
>
> irb(main):003:0> y=3D[];y<<x
> =3D> [[1]]
> irb(main):004:0> y[0].object_id
> =3D> 20774910 #the same object that x referrs to
>
> irb(main):005:0> x=3D[2]
> =3D> [2]
> irb(main):006:0> x.object_id
> =3D> 21222360 #now x refers to the newly created array
>
> irb(main):008:0> y
> =3D> [[1]]
> irb(main):007:0> y[0].object_id
> =3D> 20774910 #but y still holds a reference to the old one.
>
> irb(main):009:0> y=3D[x]
> =3D> [[2]]
> irb(main):010:0> y[0].object_id
> =3D> 21222360 #y[0] is now a reference to the same Array as x
>
> irb(main):011:0> x[0]=3D4
> =3D> 4
> irb(main):013:0> y
> =3D> [[4]] #so changes to the content of that Array are visible
> through y's reference.
>
>
> hope this helps,
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>> x =3D [1]

>
> [1] is an Array object, x is a variable referring to that array
>> y =3D []

> y referrs to a 2nd Array
>> y << x

>
> And now that array contains a reference to
>
>> x =3D [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).
>
>> end
>> def havenots
>> x =3D [1]
>> y =3D []
>> y << x
>> x[0] =3D 2 # (to this)
>> y
>> end
>> end
>>
>> I get this in irb:
>>
>> >
>> > >
>> >

>> =3D> true
>> >
>> > > a =3D Warfare.new
>> > >
>> >

>> =3D> #<Warfare:0x33a93c>
>> >
>> > > a.haves
>> > >
>> >

>> =3D> [[1]]
>> >
>> > > a.havenots
>> > >
>> >

>> =3D> [[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.
>>
>> -Jonah
>>
>>
>>

>
>

Jonah Bloch-Johnson, Aug 20, 2008