As mentioned in this answer, Array.new(size, object) creates an array with size references to the same object.
hash = Hash.new
a = Array.new(2, hash)
a[0]['cat'] = 'feline'
a # => [{"cat"=>"feline"},{"cat"=>"feline"}]
a[1]['cat'] = 'Felix'
a # => [{"cat"=>"Felix"},{"cat"=>"Felix"}]
Why does Ruby do this, rather than doing a dup or clone of object?
Each element in an array is associated with and referred to by an index. Array indexing starts at 0, as in C or Java. A negative index is assumed relative to the end of the array --- that is, an index of -1 indicates the last element of the array, -2 is the next to last element in the array, and so on.
Because that's what the documentation says it does. Note that Hash.new is only being called once, so of course there's only one Hash
If you want to create a new object for every element in the array, pass a block to the Array.new method, and that block will be called for each new element:
>> a = Array.new(2) { Hash.new }
=> [{}, {}]
>> a[0]['cat'] = 'feline'
=> "feline"
>> a
=> [{"cat"=>"feline"}, {}]
>> a[1]['cat'] = 'Felix'
=> "Felix"
>> a
=> [{"cat"=>"feline"}, {"cat"=>"Felix"}]
For certain classes that can't be modified in-place (like Fixnums) the Array.new(X, object) form works as expected and is probably more efficient (it just calls memfill instead of rb_ary_store and yielding to the block):
For more complicated objects you always have the block form (e.g. Array.new(5) { Hash.new }).
*Edit:* Modified according to the comments. Sorry for the stupid example, I was tired when I wrote that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With