2

Consider the following code:

@person = { :email => 'hello@example.com' }
temp = @person.clone
temp[:email].upcase!

p temp[:email]     # => HELLO@EXAMPLE.COM
p @person[:email]  # => HELLO@EXAMPLE.COM, why?!

# But
temp[:email] = 'blah@example.com'
p @person[:email]  # => HELLO@EXAMPLE.COM

Ruby version is: "ruby 2.1.0p0 (2013-12-25 revision 44422) [i686-linux]".

I have no idea why is it happening. Can anyone help, please?

Andrey Esperanza
  • 625
  • 1
  • 6
  • 11
  • The short answer is that `clone` is only making a shallow copy. So the reference to the string at `:email` is the same object. – Paul Richter Dec 30 '14 at 15:17
  • 1
    Thank you. I'll google a solution for making a deep copy of an object. – Andrey Esperanza Dec 30 '14 at 15:22
  • Check our [this answer](http://stackoverflow.com/a/4157635/877472), it appears to demonstrate one way of making a deep copy. There might be other good ways in other answers there too. – Paul Richter Dec 30 '14 at 15:23

1 Answers1

3

In the clone documentation you can read:

Produces a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference. clone copies the frozen and tainted state of obj.

Also pay attention to this:

This method may have class-specific behavior. If so, that behavior will be documented under the #initialize_copy method of the class.

Meaning that in some classes this behaviour can be overrided.

So any object references will be kept, instead of creating new ones. So what you want is a deep copy you can use Marshal:

temp = Marshal.load(Marshal.dump(@person))
Paulo Fidalgo
  • 21,709
  • 7
  • 99
  • 115