Because arr3 contains two identical objects, but arr4 contains two different objects.
>> arr3 = Array.new(2, Array.new(2, 0))
=> [[0, 0], [0, 0]]
>> arr3.map { |ary| ary.object_id }
=> [73703490, 73703490]
>> arr4 = [[0, 0], [0, 0]]
=> [[0, 0], [0, 0]]
>> arr4.map { |ary| ary.object_id }
=> [73670930, 73670920]
>>
Read new(size=0, default=nil)
...In the first form, if no arguments are sent, the new array will be empty. When a size and an optional default are sent, an array is created with size copies of default. Take notice that all elements will reference the same object default.
You created arr3 using the form above, while creating arr4 using the literal constructor [].
A new array can be created by using the literal constructor []. Arrays can contain different types of objects.
If you want Array::new to behave as literal construct, then go with new(size) {|index| block } form.
>> arr3 = Array.new(2){ Array.new(2, 0) }
=> [[0, 0], [0, 0]]
>> arr3.map { |ary| ary.object_id }
=> [73551460, 73551450]
>>