Strange behaviour with array of arrays

Please observe the following code:

# Create an array of arrays by explicitly stating values
test1 = [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

# Create an array of arrays using new method
test2 = Array.new(3, Array.new(3))
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

#Both arrays appear to be equal
test1 == test2 => true

# Modifying one of values behaves as expected
test1[1][1] = true => true
test1 => [[nil, nil, nil], [nil, true, nil], [nil, nil, nil]]

# Modifying one of values behaves strangely
test2[1][1] = true => true
test2 => [[nil, true, nil], [nil, true, nil], [nil, true, nil]]

Can anyone explain why this is happening as I don't understand why the
two array should behave differently? This is assuming this isn't a
bug.

Please observe the following code:

# Create an array of arrays by explicitly stating values
test1 = [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

# Create an array of arrays using new method
test2 = Array.new(3, Array.new(3))
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

#Both arrays appear to be equal
test1 == test2 => true

# Modifying one of values behaves as expected
test1[1][1] = true => true
test1 => [[nil, nil, nil], [nil, true, nil], [nil, nil, nil]]

# Modifying one of values behaves strangely
test2[1][1] = true => true
test2 => [[nil, true, nil], [nil, true, nil], [nil, true, nil]]

Can anyone explain why this is happening as I don't understand why the
two array should behave differently? This is assuming this isn't a
bug.

Let me see if I can get Ruby to explain this for you:

>> a = [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
>> a.map { |e| e.object_id }
=> [3797062, 3797052, 3797042]
>> a = Array.new(3, Array.new(3))
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
>> a.map { |e| e.object_id }
=> [3779002, 3779002, 3779002]
>> a = Array.new(3) { Array.new(3) }
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
>> a.map { |e| e.object_id }
=> [3760242, 3760232, 3760222]

As you can see, the new(n, obj) constructor uses the same object over and over again. You want the block form (shown last) instead.

James Edward Gray II

···

On Jan 2, 2007, at 3:14 PM, Dan Stevens (IAmAI) wrote:

The syntax you want is this ...

test2 = Array.new(3) {Array.new(3)}

This will create a new array of three elements and then create a a new
array object for each element of test2

test2 = Array.new(3, Array.new(3))

This will create a new array of three elements but use the same object
for element of test2

Blessings,
TwP

···

On 1/2/07, Dan Stevens (IAmAI) <dan.stevens.iamai@gmail.com> wrote:

Please observe the following code:

# Create an array of arrays by explicitly stating values
test1 = [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

# Create an array of arrays using new method
test2 = Array.new(3, Array.new(3))
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]]

#Both arrays appear to be equal
test1 == test2 => true

# Modifying one of values behaves as expected
test1[1][1] = true => true
test1 => [[nil, nil, nil], [nil, true, nil], [nil, nil, nil]]

# Modifying one of values behaves strangely
test2[1][1] = true => true
test2 => [[nil, true, nil], [nil, true, nil], [nil, true, nil]]

Can anyone explain why this is happening as I don't understand why the
two array should behave differently? This is assuming this isn't a
bug.