Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Ruby, why does Array.new(size, object) create an array consisting of multiple references to the same object?

Tags:

arrays

ruby

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?

like image 587
Andrew Grimm Avatar asked Jan 09 '11 22:01

Andrew Grimm


People also ask

How does array work in Ruby?

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.


2 Answers

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"}]
like image 138
Gareth Avatar answered Oct 31 '22 00:10

Gareth


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.

like image 26
Michael Kohl Avatar answered Oct 31 '22 01:10

Michael Kohl