When to use dup, and when to use clone in Ruby?
Asked Answered
I

2

13

What's the difference between Ruby's dup and clone methods? describes the difference in the behavior of dup and clone. But when should I use dup, and when should I use clone instead?

Examples from actual projects which discuss why they used dup rather than clone, or vice versa, would be ideal for this question.

Alternatively, an explanation of why the two different methods exist would be helpful. This could refer to statements from the creators of Ruby, or an examination of methods like dup and clone in languages that influenced Ruby.

Inverson answered 1/8, 2012 at 0:0 Comment(1)
Possible duplicate of What's the difference between Ruby's dup and clone methods?Etamine
N
8

It is true that clone copies the frozen state of an object, while dup does not:

o = Object.new
o.freeze

o.clone.frozen?
#=> true

o.dup.frozen?
#=> false

clone will also copy the singleton methods of the object while dup does not:

o = Object.new
def o.foo
  42
end

o.clone.respond_to?(:foo)
#=> true

o.dup.respond_to?(:foo)
#=> false

Which leads me to the assumption that clone is sometimes understood as to provide a "deeper" copy than dup. Here are some quotes about the topic:

Comment on ActiveRecord::Base#initialize_dup from Rails 3:

Duped objects have no id assigned and are treated as new records. Note that this is a "shallow" copy as it copies the object's attributes only, not its associations. The extent of a "deep" copy is application specific and is therefore left to the application to implement according to its need.

An article about deep copies in Ruby:

There is another method worth mentioning, clone. The clone method does the same thing as dup with one important distinction: it's expected that objects will override this method with one that can do deep copies.

But then again, theres deep_dup in Rails 4:

Returns a deep copy of object if it's duplicable. If it's not duplicable, returns self.

and also ActiveRecord::Core#dup and #clone in Rails 4:

clone — Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied. [...] If you need a copy of your attributes hash, please use the #dup method.

Which means that here, the word dup is used to refer to a deep clone again. As far as I can see, there seems to be no consensus in the community, except that you should use clone and dup in the case when you need a specific side effect of either one.

Finally, I see dup much more often in Ruby code than clone. I have never used clone so far, and I won't until I explicitly need to.

Nyctalopia answered 28/5, 2014 at 20:11 Comment(1)
For now it looks to me like you've got to use dup, unless you have reasons to use clone (dup seems to be simpler). But maybe that's because I'm now concerned with duplicating a hash. So I don't care about frozen state and a singleton class.Trio
K
5

Both DUP & CLONE can be used to create shallow copy of an object. Both copies the instance variables of obj. But we need to be selective in their usage.

Few difference between these are

1) CLONE copies both FROZEN and TAINTED state of an object, where as DUP only copies TAINTED state of an object.

2) With CLONE you can copy any singleton methods of an object but DUP does not support this.

CLONE is used to duplicate an object, including its internal state, DUP typically uses the class of the descendent object to create the new instance.

I had some bitter experience while using DUP for duplicating an ActiveRecord row, this ended up in losing the original one the same worked fine with CLONE.

As I wrapped myself in confusion, I found it clear in an Article of Open Source is Wide Open

Karat answered 1/8, 2012 at 4:17 Comment(4)
"There are three manners to copy in Ruby: #dup, #clone and '='." - How does = copy?Inverson
I don't get deeper in how '=' copy, but it makes a shallow copy too. Here is a good example for start, but in summary the assignment operator doesn't make a copy of the value, it simply copies the reference to the objectKarat
Just a note: Marshal::load(Marshal.dump(foo)) works, but may cause trouble with database models.Sectional
Operator = does not make a shallow copy, it will just copy the object reference! That statement is just plain wrong. Also: the difference between #dup and #clone is just handling of the frozen state. I think it is a bad idea to implement different copying algorithms for both - either it's both deep or shallow. And where are the numbers about a performance difference between the two? I would be very surprised to see significant differences because both do basically the same. Can you point at numbers?Harragan

© 2022 - 2024 — McMap. All rights reserved.