Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Both dup and clone return different objects, but modifying them alters the original object

I have an array of values that I use as a reference for order when I'm printing out hash values. I'd like to modify the array so that the array values are "prettier". I figured I'd just dup or clone the array, change the values and the original object would remain unchanaged. However (in irb)...

@arr = ['stuff', 'things']
a = @arr.clone
b = @arr.dup

So, at the very least, a and @arr are different objects:

a.object_id == @arr.object_id
=> false

But now it gets strange

a[0].capitalize!
a
=> ['Stuff', 'things']
@arr
=> ['Stuff', 'things'] ##<-what?
b
=> ['Stuff', 'things']## <-what???

ok... so modifying one changes the others, lets change it back?

a[0] = 'stuff'
a
=> ['stuff', 'things']
@arr
=> ['Stuff', 'things'] ## <- WHAT?????

For completeness b[1].capitalize! has the same effect, capitalizing all three array's second position

So... does the bang on the end of capitalize make it extra potent? Enough to cross over to other objects?? I know of other ways of doing this, but this just seemed extremely odd to me. I assume this has something to do with being a "shallow copy". Suggestions on the best way to do this?

like image 708
jearl Avatar asked Sep 19 '12 20:09

jearl


People also ask

What's the difference between DUP and clone in Ruby?

Have you ever wondered what the differences are between #dup and #clone in Ruby? They both create a shallow copy of an object (meaning that they don't copy the objects that might be referenced within the copied object). However, #clone does two things that #dup doesn't:

What is the difference between DUP () and DUP () methods?

Exploring the sameness & difference between two things is a great way to improve your understanding. Both methods copy an object, the difference is that dup doesn’t copy the object attributes.

How to change an object but keep a copy of it?

If you want to change an object but keep a copy of the original then you can clone it. For example. You may want an array with all the elements but the first one. Both examples allow you to keep the original array.

How do I ignore the frozen status of the cloned object?

Ruby 2.4 includes an option for clone to ignore the frozen status of the cloned object. There is more to copying an object than meets the eye. When you make a copy, with either dup or clone, you are making a shallow copy. This means that objects contained within other objects won’t be copied.


1 Answers

dupand clone make new instances of the arrays, but not of the content, it is no deep copy.

See:

array0 = ['stuff', 'things']
array1 = array0.clone
array2 = array0.dup

puts "Array-Ids"
p array0.object_id
p array1.object_id
p array2.object_id

puts "Object ids"
array0.each_with_index{|_,i|
  p array0[i].object_id
  p array1[i].object_id
  p array2[i].object_id
  p '--------'
}

The elements inside the array share the same object_id - they are the same object. The arrays have different object ids.

When you a[0].capitalize! you modify an object, which is part in three different arrays.

See also

  • Duplicating a Ruby array of strings
  • Deep copy of arrays in Ruby
  • How to create a deep copy of an object in Ruby?
like image 75
knut Avatar answered Sep 19 '22 12:09

knut