breaking into the unknown…

copy object in ruby

Leave a comment

When ever, you pass any object to any other method for manipulation, you should pass its copy rather then the original object to prevent any risk on the original object. See the below example.

we have below classes in bank_account.rb

class BankAccount
  attr_accessor :name, :balance
  def initialize(name,balance)
    @name = name
    @balance = balance

class Invoice
  def print_account_holder_name(account_holder)
    account_holder.balance = 1000000

BankAccount is the class which hold detail of accounts. Invoice class, generate the account report. Let us demonstrate the involved risk on console

1.9.3-p194 :014 > load “/home/arun/Documents/bank_account.rb” # give path of your bank_account.rb
1.9.3-p194 :016 > a =“arun”, 10000)
=> #<BankAccount:0xc9553d8 @name=”arun”, @balance=10000>
1.9.3-p194 :017 >
1.9.3-p194 :019 > a.balance
=> 1000000

So you can see that, when print_account_holder_name method of invoice class is passed object of BankAccount class, it accidently or intentionally(in our case), increased the balance from 10000  to 10000000 . This can be avoided by passing the copy of object rather then the original object.

With the above background, we now understand the need of creating copy of object before passing to any other method or doing any manipulation over it. Let us see how we can do that i,e copy a object.

In ruby, everything is a object, even the data types. consciously or unconsciously, you have many a time created copy of these objects with assignment operator while programming.

try this in console

1.9.3-p194 :020 > a = 1
=> 1
1.9.3-p194 :023 > b = a
=> 1
1.9.3-p194 :024 > b += 1
=> 2
1.9.3-p194 :025 > a
=> 1
1.9.3-p194 :026 > b
=> 2

You can see that, you created b as a copy of a, when you add 1 to b, a do not changed i,e the manipulation occurred only on the copy b . But this way of creating copy work only for plain data type integer, string , text etc.

See again the above with a array value.

1.9.3-p194 :027 > a = [1,2]
=> [1, 2]
1.9.3-p194 :028 > b = a
=> [1, 2]
1.9.3-p194 :029 > b << 3
=> [1, 2, 3]
1.9.3-p194 :030 > a
=> [1, 2, 3]

So you can see that, creating copy with assignment operator = not worked and array assigned to a also get changed when the copy b is modified. This is because the Array object is not a primary data type. The assignment operator doesn’t make a copy of the value, it simply copies the reference to the Array object. The a and b variables are now references to the same Array object, any changes in either variable will be seen in the other.

Here dup and clone come to our rescue

1.9.3-p194 :031 > a = [1,2]
=> [1, 2]
1.9.3-p194 :032 > b = a.dup # a.clone also work
=> [1, 2]
1.9.3-p194 :033 > b << 3
=> [1, 2, 3]
1.9.3-p194 :034 > a
=> [1, 2]

So now you can see that with dup or clone, the changes on the copy not alter the original object a . Good… let us check the real scenario we have created in our  bank_account.rb.

1.9.3-p194 :039 > load “/home/arun/Documents/bank_account.rb”
=> true
1.9.3-p194 :040 > a =“arun”, 10000)
=> #<BankAccount:0xc94549c @name=”arun”, @balance=10000>
1.9.3-p194 :041 > b = a.clone
=> #<BankAccount:0xc936ce4 @name=”arun”, @balance=10000>
1.9.3-p194 :042 > c = a.dup
=> #<BankAccount:0xc929fa8 @name=”arun”, @balance=10000>
1.9.3-p194 :043 >
1.9.3-p194 :044 >
1.9.3-p194 :046 > a.balance
=> 10000

O.K, so this time we pass the copy b(created with dup) and copy c (created with clone) to the print_account_holder_name method of invoice class, and you can see that the balance of the original object a is secure .

Great…we will now onward create a copy of sensitive object before handing over it to any other interface for manipulation. But what is this … both dup and clone seems to doing the same thing : – copying the object . Yaa… superficially they are same, but do exhibit different behaviour. the difference can be stated in a single line as below.

clone maintain internal characteristic of copied object but dup do not .

Let us see the difference in the console.

=> dup do not maintain the frozen state of the object

1.9.3-p194 :011 > a =“arun”, 10000)
=> #<BankAccount:0x9997470 @name=”arun”, @balance=10000>
1.9.3-p194 :012 > a.freeze
=> #<BankAccount:0x9997470 @name=”arun”, @balance=10000>
1.9.3-p194 :013 > a.frozen?
=> true
1.9.3-p194 :014 > b = a.dup
=> #<BankAccount:0x99a1254 @name=”arun”, @balance=10000>
1.9.3-p194 :015 > b.frozen?
=> false
1.9.3-p194 :016 > c = a.clone
=> #<BankAccount:0x99a5cf0 @name=”arun”, @balance=10000>
1.9.3-p194 :017 > c.frozen?
=> true

So, you can see that, object a is frozen, but when it id copied with dup it become unfrozen, but remain same when copied with clone.


=> dup do not copy the singleton method of the object .

1.9.3-p194 :018 > a =“arun”, 10000)
=> #<BankAccount:0x99b1e38 @name=”arun”, @balance=10000>
1.9.3-p194 :019 > def a.iam_singleton
1.9.3-p194 :020?>   end

1.9.3-p194 :021 > a.methods
=> [:iam_singleton, :name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone…]

1.9.3-p194 :023 > b = a.dup
=> #<BankAccount:0x99c3c3c @name=”arun”, @balance=10000>
1.9.3-p194 :024 > b.methods
=> [:name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone…]

1.9.3-p194 :025 > c = a.clone
=> #<BankAccount:0x99d2110 @name=”arun”, @balance=10000>
1.9.3-p194 :026 > c.methods
=> [:iam_singleton, :name, :name=, :balance, :balance=,:clone, :dup, :initialize_dup, :initialize_clone…]

so we have added iam_singleton method to the object a . It is available to the copy c created with clone but not available to copy b created with dup.

NOTE : You can’t make copy of all the object. for example fixnum can’t be copied

 1.9.3-p194 :033 > 1.dup
TypeError: can’t dup Fixnum
1.9.3-p194 :033 > 1.clone
TypeError: can’t clone Fixnum


NOTE : you can customize the dup and clone method by redefining initialize_dup and initialize_clone method in your class, so overriding the original behaviour. Both initialize_dup and initialize_clone call initialize_copy method internally we now know the difference between dup and clone. But which one we should use. Well it is upto you. Personally, I prefer dup, as I know that Iam having only the copy of the object, so I can mess with it. I do not want any limitation on the copy I’ am having . Limitation is always a pain..isn’t it…go with dup. 🙂





Author: arunyadav4u

over 7 years experience in web development with Ruby on Rails.Involved in all stage of development lifecycle : requirement gathering, planing, coding, deployment & Knowledge transfer. I can adept to any situation, mixup very easily with people & can be a great friend.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s