Forum: Ruby Bug or not a bug? array*=int

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Kyle S. (Guest)
on 2008-10-29 17:31
(Received via mailing list)
So I'm wondering, is this a bug, or not a bug, or a type-o in the docs?

According to http://www.ruby-doc.org/core/classes/Array.html
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]]
Martin DeMello (Guest)
on 2008-10-29 18:13
(Received via mailing list)
On Wed, Oct 29, 2008 at 8:30 AM, Kyle S. <removed_email_address@domain.invalid>
wrote:
> So I'm wondering, is this a bug, or not a bug, or a type-o in the docs?
>
> According to http://www.ruby-doc.org/core/classes/Array.html
> 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
Kyle S. (Guest)
on 2008-10-29 18:29
(Received via mailing list)
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*?

:)
Robert K. (Guest)
on 2008-10-29 18:55
(Received via mailing list)
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
Brian C. (Guest)
on 2008-10-29 19:38
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)
Stefan R. (Guest)
on 2008-10-30 14:23
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*?
>
> :)

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
Kyle S. (Guest)
on 2008-10-30 20:56
(Received via mailing list)
On Thu, Oct 30, 2008 at 7:22 AM, Stefan R. 
<removed_email_address@domain.invalid>
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 :) common pitfalls should be noted
all over the place in the docs.

--Kyle
This topic is locked and can not be replied to.