The Complete Guide to Create a Copy of an Object in Ruby: Part I

Tech - RubyCademy
RubyCademy
3 min readJan 4, 2019

--

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

  • shallow copy and deep copy
  • dup and clone
  • dup vs clone

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 the Forwardable 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! 🔔

🔗 Ruby Mastery by RubyCademy

Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.

💚

--

--