Bug or feature

There has probably been some discussion about this problem so sorry if I
am repeating but it is so crucial that should be mention every once in a
while.

This simple example:

a=[‘0’]
1.upto(2) do
b = a.clone
c = a.clone
b[0] << ‘1’
c[0] += ‘2’
end
p a

yields [‘011’] in ruby 1.8.6 and 1.9.3. I think that it should be [‘0’]

I understand the difference between << an += operator but shouldn’t
clone method make a duplicate of object a, without any link to original
object.

Or am I missing something.

by
TheR

On Tue, Sep 18, 2012 at 9:36 AM, Damjan R. [email protected]
wrote:

b[0] << ‘1’
Or am I missing something.
Yes. #clone is just shallow copy.

irb(main):002:0> a=[‘foo’, ‘bar’]
=> [“foo”, “bar”]
irb(main):003:0> a.map &:object_id
=> [-1072256208, -1072256218]
irb(main):004:0> b = a.clone
=> [“foo”, “bar”]
irb(main):005:0> b.map &:object_id
=> [-1072256208, -1072256218]
irb(main):006:0> a.zip(b).all? {|x,y| x.equal? y}
=> true

For full object tree copy you can do

irb(main):007:0> c = Marshal.load(Marshal.dump(a))
=> [“foo”, “bar”]
irb(main):008:0> c.map &:object_id
=> [-1072289088, -1072289108]
irb(main):009:0> a.zip(c).all? {|x,y| x.equal? y}
=> false

Kind regards

robert

Damjan R. wrote in post #1076429:

I understand the difference between << an += operator but shouldn’t
clone method make a duplicate of object a, without any link to original
object.

a.clone duplicate the object ‘a’ , but each elements of the array are
not
cloned.

Doing b[0] << ‘1’ you affect an object which is referenced by a
but b << ‘1’ you affect the structure of b, which do not impact a

Regard,

when you only have a flat array, you could do:
b = a.map(&:clone)

but beware, some objects like fixnumbers dont want to be cloned

On Tue, Sep 18, 2012 at 12:19 PM, Hans M. [email protected]
wrote:

when you only have a flat array, you could do:
b = a.map(&:clone)

but beware, some objects like fixnumbers dont want to be cloned

Well, you can do

b = a.map {|x| x.clone rescue x}

But that is still not a deep copy - unless types of objects in a
implement deep copy in their #clone method.

Kind regards

robert

Robert K. wrote in post #1076432:

For full object tree copy you can do

irb(main):007:0> c = Marshal.load(Marshal.dump(a))

Why is real cloning not implemented in ruby, since this fake cloning can
lead to a lot of troubles.

by
TheR

The line:

a = [‘0’]

  1. First tells ruby to create the string at some location in memory:

1033 Maple Dr.

 '0'
  1. Then ruby inserts the address in a new
    array:

[1033 Maple Dr.]

  1. Then ruby does the assignment and makes the variable ‘a’ refer to
    that array:

a -------> [1033 Maple Dr.]

The line:

b = a.clone

  1. First, creates a new array that is a copy of the ‘a’ array:

[1033 Maple Dr.]

  1. Then ruby does the assignment and makes b refer to the new array:

b -----> [1033 Maple Dr.]

So the overall picture becomes:

a -----> [1033 Maple Dr.] 1033 Maple Dr.
-------
‘0’
b -----> [1033 Maple Dr.]

a and b refer to two different arrays, but what’s inside the arrays is
the same.
So when you use b to change the string that resides at 1033 Maple Dr.,
that effects ‘a’ because it also contains the address 1033
Maple Dr.

On Tue, Sep 18, 2012 at 8:44 PM, Damjan R. [email protected]
wrote:

Robert K. wrote in post #1076432:

For full object tree copy you can do

irb(main):007:0> c = Marshal.load(Marshal.dump(a))

Why is real cloning not implemented in ruby, since this fake cloning can
lead to a lot of troubles.

What do you mean - “real cloning”? Shallow copy is as real as deep
copy. They are just different concepts. If you think about it for a
moment a deep copy is significantly more difficult to realize
(especially with object graphs which have different paths to the same
instance). It is totally reasonable to provide a shallow copy as
default - btw. Java does it, too.

And you can simply create your deep copy method:

class Object
def clone_deep
Marshal.load(Marshal.dump(self))
end
end

Kind regards

robert

On Wed, Sep 19, 2012 at 8:00 AM, Damjan R. [email protected]
wrote:

So there is a good reason not to implement object duplication (deep
cloning). Results may be unpredictable so better don’t do it.

As I said elsewhere: I prefer custom logic tailored to the use case
and not a general mechanism which simply does a deep copy. That’s
likely more efficient and less error prone than the deep copying
approach.

Although I never liked the argument if it is good for them than it is
good for us.

I am not sure I understand what you mean here.

Cheers

robert

Robert K. wrote in post #1076534:

On Tue, Sep 18, 2012 at 8:44 PM, Damjan R. [email protected]
wrote:

Robert K. wrote in post #1076432:

For full object tree copy you can do

irb(main):007:0> c = Marshal.load(Marshal.dump(a))

Why is real cloning not implemented in ruby, since this fake cloning can
lead to a lot of troubles.

What do you mean - “real cloning”? Shallow copy is as real as deep
copy. They are just different concepts. If you think about it for a
moment a deep copy is significantly more difficult to realize
(especially with object graphs which have different paths to the same
instance). It is totally reasonable to provide a shallow copy as
default - btw. Java does it, too.

And you can simply create your deep copy method:

class Object
def clone_deep
Marshal.load(Marshal.dump(self))
end
end

Kind regards

robert

So there is a good reason not to implement object duplication (deep
cloning). Results may be unpredictable so better don’t do it.

Although I never liked the argument if it is good for them than it is
good for us.

by
TheR

On Wed, Sep 19, 2012 at 9:04 PM, Damjan R. [email protected]
wrote:

Although I never liked the argument if it is good for them than it is
good for us.

I am not sure I understand what you mean here.

Your statement that Java does the same kind of cloning.

Ah, OK. Although I rather meant that the example of Java demonstrates
that the concept of a providing shallow copy only is not unique to
Ruby and that this - together with the other arguments - should be
taken as a hint that there might be a good reason deep copy is not
provided out of the box.

Cheers

robert

Although I never liked the argument if it is good for them than it is
good for us.

I am not sure I understand what you mean here.

Your statement that Java does the same kind of cloning.

by
TheR

dclone()

See: Overriding Object#clone vs. Overriding Object#dup for Deep-Cloning - Ruby - Ruby-Forum

~