In this article we’re going to explore the following topics:

shallow copy and deep copy

dup and clone

and dup vs clone

Before to start

I’m thrilled to share with you our latest project: Fun Facts about Ruby — Volume 1

Please feel free to spread the word and share this post! 🙏

Thank you for your time!

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 to 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 has 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

The Object#dup method 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 new 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 the Forwardable module.

Object#clone

The Object#clone method 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, the Object#clone method 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 to copy 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 the Part II, we’re going to talk about deep copy and object marshalling in Ruby.

Voilà!

ONE MORE THING ⬇

Feel free to subscribe here: www.rubycademy.com