Did you know that you can copy an object in Ruby? Not only that, but there are two different methods to do this!
These methods are:
dup
clone
We will explore the differences in a moment, but first…
Why would you want to clone an object?
Many objects in Ruby are mutable, you can change them.
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.
One way to do this:
a = [1,2,3,4,5] a[1..-1] # [2,3,4,5]
Another way would be:
b = a.clone b.shift # [1] b # [2,3,4,5]
Both examples allow you to keep the original array.
Frozen Objects
Dup & clone are not an alias of each other like it happens with other Ruby methods (map/collect), there a few small differences between them.
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.
What object attributes?
- frozen status
- tainted status
- singleton class
Here’s an example:
a = Object.new.freeze b = a.dup b.frozen? # false b = a.clone b.frozen? # true
Ruby 2.4 includes an option for clone
to ignore the frozen status of the cloned object.
Example:
a.clone(freeze: true) a.clone(freeze: false)
Deep vs Shallow Copying
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.
In other words:
If you have an array of strings, only the array will be copied, not the strings themselves.
See for yourself:
original = %w(apple orange banana) copy = original.clone original.map(&:object_id) # [23506500, 23506488, 23506476] copy.map(&:object_id) # [23506500, 23506488, 23506476]
The object ids are the same even after cloning the array, so we have the same strings.
You could solve that with this:
strings.clone.map(&:clone)
This results on both the array & the strings being cloned, but notice that this only goes one level deep. You can try the deep_dup method from ActiveSupport as an alternative.
Summary
You have learned about cloning objects in Ruby! Including the differences between the dup & clone methods, and shallow copy vs deep copy.
Thanks for reading!