Bug or not a bug? array*=int

So I’m wondering, is this a bug, or not a bug, or a type-o in the docs?

According to class Array - RDoc Documentation
array*int “[R]eturns a new array built by concatenating the int
copies of self.”
Copies should be brand new independent copies, right?

foo=[[nil,nil,nil]]returns a new array built by concatenating the int
copies of self.
foo*=3
#Foo is now.
#[[nil,nil,nil],

[nil,nil,nil],

[nil,nil,nil]]

foo[1][1]=12
#Foo is now
#[[nil,12,nil],

[nil,12,nil],

[nil,12,nil]]

#But I would have expected it to be
#[[nil,nil,nil],

[nil,12,nil],

[nil,nil,nil]]

On Wed, Oct 29, 2008 at 8:30 AM, Kyle S. [email protected]
wrote:

So I’m wondering, is this a bug, or not a bug, or a type-o in the docs?

According to class Array - RDoc Documentation
array*int “[R]eturns a new array built by concatenating the int
copies of self.”
Copies should be brand new independent copies, right?

No, copies are shallow copies. Consider, for example

irb(main):002:0> class A; attr_accessor :a; end
=> nil
irb(main):003:0> a = A.new
=> #<A:0xb7c65b44>
irb(main):004:0> a.a = 10
=> 10
irb(main):005:0> foo = [a]
=> [#<A:0xb7c65b44 @a=10>]
irb(main):006:0> foo *= 3
=> [#<A:0xb7c65b44 @a=10>, #<A:0xb7c65b44 @a=10>, #<A:0xb7c65b44 @a=10>]
irb(main):007:0> a.a = 20
=> 20
irb(main):008:0> foo
=> [#<A:0xb7c65b44 @a=20>, #<A:0xb7c65b44 @a=20>, #<A:0xb7c65b44 @a=20>]

martin

Ahh.
And upon not being lazy and looking at the C, I see this…
ary2 = ary_new(rb_obj_class(ary), len);

Which I’m guessing is equivalent to this in ruby (which I already knew
would return the same array len times)
ary2=Array.new(ary,len)

Any chance the document maintainer could slip the word “shallow” into
the description of array*?

:slight_smile:

Robert K. wrote:

deep copy is more complex

… and in many cases impossible (e.g. open files/sockets; procs/blocks;
any object with a singleton class)

On 29.10.2008 17:26, Kyle S. wrote:

Ahh.
And upon not being lazy and looking at the C, I see this…
ary2 = ary_new(rb_obj_class(ary), len);

Which I’m guessing is equivalent to this in ruby (which I already knew
would return the same array len times)
ary2=Array.new(ary,len)

Any chance the document maintainer could slip the word “shallow” into
the description of array*?

Dunno. But all (or almost all) copies (e.g. dup, clone, Enumerable#map,
Enumerable#select) do shallow copying only. So shallow is the rule and
not particularly exceptional - as it is also more efficient and deep
copy is more complex (i.e. deciding when to create a new object or just
copy the reference). There are quite a few discussions of this topic in
the archives…

For deep copies the idiom probably most often used is

copy = Marshal.load(Marshal.dump(obj))

Kind regards

robert

On Thu, Oct 30, 2008 at 7:22 AM, Stefan R. [email protected]
wrote:

As mentioned by others, shallow is the default (also to my knowledge in
most OO languages).
The moment you wish for deep copy is usually the moment you should
consider writing a proper class instead of deeply nesting
arrays/hashes/…

Regards
Stefan

Stefan, while I agree that in general you should write a proper class,
the case I was talking about is a completely valid and normal use of
multi-dimensional arrays in ruby. I’m guessing that duplicating a row
in an array is not a rare occurrence either. I was just saying that
maybe a mention of this should be added to the standard docs, as it’s
a common pitfall. Bits are cheap :slight_smile: common pitfalls should be noted
all over the place in the docs.

–Kyle

Kyle S. wrote:

Ahh.
And upon not being lazy and looking at the C, I see this…
ary2 = ary_new(rb_obj_class(ary), len);

Which I’m guessing is equivalent to this in ruby (which I already knew
would return the same array len times)
ary2=Array.new(ary,len)

Any chance the document maintainer could slip the word “shallow” into
the description of array*?

:slight_smile:

As mentioned by others, shallow is the default (also to my knowledge in
most OO languages).
The moment you wish for deep copy is usually the moment you should
consider writing a proper class instead of deeply nesting
arrays/hashes/…

Regards
Stefan