Search code examples
rubyclonestring-substitution

Why does String::sub!() change the original of a cloned object in Ruby?


I have a struct in my Ruby code that looks somewhat like this

Parameter = Struct.new(:name, :id, :default_value, :minimum, :maximum)

later, I create an instance of this struct using

freq = Parameter.new('frequency', 15, 1000.0, 20.0, 20000.0)

At some point, I need an exact duplicate of this struct, so I call

newFreq = freq.clone

Then, I change newFreq's name

newFreq.name.sub!('f', 'newF')

Which, miraculously, changes freq.name, too!

A simple assignment like newFreq.name = 'newFrequency' does not change freq.

Is this the way this is supposed to work?

Edit: Is it a good idea to use a class instead of a struct and overload clone to make a deep copy?


Solution

  • newFreq is a shallow copy of freq. That means that each of the references stored inside of newFreq points to the object as the ones stored in freq. You can change where the references point independantly (newFreq.name = newFreq.name.sub 'f','newF'), but if you call a method that mutates the object, both newFreq and freq will be affected.

    See also http://en.wikipedia.org/wiki/Object_copy