The Complete Guide to Create a Copy of an Object in Ruby: Part I
In this article we’re going to explore the following topics:
- shallow copy and deep copy
dup
andclone
dup
vsclone
Introduction
The principle of copying a value or an object is a key concept of any programming language.
A lot of principles to copy objects and values have been implemented through time.
In this series of articles, we are going to focus on shallow copy and deep copy.
We’ll also cover what Ruby provides to use these principles.
Shallow copy vs. Deep copy
Let’s have a look at what are these 2 principles.
Shallow copy
Shallow copy is based on the fact that a bit-wise copy of an object is generated.
The freshly created object contains an exact copy of the values in the copied object.
If a variable of the copied object is a reference to another object, then just the reference address of the object is copied.
Deep copy
A deep copy works as a shallow copy.
In addition, all the objects pointed by reference in the copied object will also be copied.
A proper definition of a deep copy would be:
A deep copy occurs when an object is copied along with the objects to which it refers.
dup and clone methods
Now that we’re more familiar with shallow and deep copy principles, then let’s discover what Ruby proposes to copy an object.
Note that this article only covers shallow copy. Deep copy will be covered in the Part II.
Object#dup
Object#dup
returns a shallow copy of the calling object
In the above example, a shallow copy of collection1
is stored in collection2
by assigning the return value of collection1.dup
to collection2
.
We can see that collection2.first
contains a reference to obj1
.
So when obj1
is modified, then collection2.first
get impacted by the modification.
Note that, internally, the Object#dup
method calls the initialize_copy
method of the new object copy.
You can implement this method to interact with the copy of the original object
produces
initialize copy
Here, by implementing the Collection#initialize_copy
method, we can interact with the newly generated object during the copy of the original object.
This method call occurs when collection1.dup
is called.
Feel free to have a look to the
Forwardable module in Ruby
article if you are not familiar with theForwardable
module.
Object#clone
Object#clone
returns a shallow copy of the calling object
In the above example, a shallow copy of collection1
is stored in collection2
by assigning the return value of collection1.clone
to collection2
.
We can see that collection2.first
is a reference to obj1
.
So when obj1
is modified, then collection2.first
get impacted by the modification.
Note that internally, Object#clone
also calls an initialize_copy
hook method on the calling object.
So, what’s the difference between these two methods ?!
clone vs dup
While nearly identical, clone
does three more things than dup
.
Object#freeze
In clone
, the frozen state of the object is also copied
You can avoid copying the frozen state by passing the frozen:
keyword argument with false
to the Object#clone
method.
Object#extend
When using Object#clone
, any modules that the object has been extended with will be copied.
This won’t be the case with Object#dup
Feel free to have a look to the
Module in Ruby
article if you are not familiar with modules in Ruby.
Object-level methods
When using Object#clone
, all the object-level methods of the original object are copied.
This won’t be the case with Object#dup
Part II
In Part II, we’re going to talk about deep copy and object marshaling in Ruby.
Ruby Mastery
We’re currently finalizing our first online course: Ruby Mastery.
Join the list for an exclusive release alert! 🔔
Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.
💚