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.
First tells ruby to create the string at some location in memory:
1033 Maple Dr.
'0'
Then ruby inserts the address in a new
array:
[1033 Maple Dr.]
Then ruby does the assignment and makes the variable ‘a’ refer to
that array:
a -------> [1033 Maple Dr.]
The line:
b = a.clone
First, creates a new array that is a copy of the ‘a’ array:
[1033 Maple Dr.]
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.
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
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.
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.
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.