Project

General

Profile

Actions

Feature #4514

open

#deep_clone and #deep_dup for Objects

Added by wardrop (Tom Wardrop) over 13 years ago. Updated almost 7 years ago.

Status:
Assigned
Target version:
-
[ruby-core:<unknown>]

Description

=begin
There's often a need to do a deep clone of an object, especially of Hash/Array trees. The typical work around to the lack of this functionality is to Marshall and then Unmarshall (e.g. Marshal::load(Marshal::dump(self)) ), which incurs more overhead than it probably should, and is not very semantic. My suggestion is to either provide #deep_clone and #deep_dup methods on the Object class, or to at least provide equivalent functionality for Hashes and Arrays, such as possibly a #deep_merge method for Hash. The exact implantation is not a large concern of mine; I'll let the experts determine the best method of achieving the desired outcome.
=end

Actions #1

Updated by wardrop (Tom Wardrop) over 12 years ago

No one wants to add anything?

Updated by shyouhei (Shyouhei Urabe) over 12 years ago

Some thoughts

  • #deep_merge is a Rails method. If you only need Arrays + Hashs to be deep_dup'able, chances are they also should go into Rails.
  • It is not always obvious what a "deep" copy is. For instance it is very hard to define one for a Proc instance.
  • Recursive duplication may not be that simple to implement than you imagine. For instance an Array can contain itself:
    r = [].tap {|r| r << r }
    How do you copy it deeply?
Actions #3

Updated by marcandre (Marc-Andre Lafortune) over 12 years ago

Hi,

Shyouhei Urabe wrote:

  • It is not always obvious what a "deep" copy is. For instance it is very hard to define one for a Proc instance.

Agreed, but since Procs do no "contain" anything, I'd say Proc#deep_dup == Proc#dup (except that it would call deep_dup on any instance variables, I imagine).

  • Recursive duplication may not be that simple to implement than you imagine. For instance an Array can contain itself:
    r = [].tap {|r| r << r }
    How do you copy it deeply?

That shouldn't be too hard, we simply maintain a hash with the ids of objects being cloned as keys and with the corresponding new copies as values. I would have fun implementing it. Note that Marshal::load(Marshal::dump(r)) works for recursive arrays and so does YAML serialization.

I can attest that the question comes up from time to time on StackOverflow, so it is something quite a bit of people wonder about.

Updated by kstephens (Kurt Stephens) over 12 years ago

Marc-Andre Lafortune wrote:

Shyouhei Urabe wrote:

  • It is not always obvious what a "deep" copy is. For instance it is very hard to define one for a Proc instance.
  • Recursive duplication may not be that simple to implement than you imagine. For instance an Array can contain itself:
    r = [].tap {|r| r << r }
    How do you copy it deeply?

That shouldn't be too hard, we simply maintain a hash with the ids of objects being cloned as keys and with the corresponding new copies as values. I would have fun implementing it. Note that Marshal::load(Marshal::dump(r)) works for recursive arrays and so does YAML serialization.

See https://github.com/kstephens/red_steak/blob/master/lib/red_steak/copier.rb

The problem is how to control how "deep" a copier should go, which objects need to have identity maintained and which objects are simply containers. The programmer needs control via some protocol with the copier.

Updated by mame (Yusuke Endoh) over 12 years ago

  • Status changed from Open to Assigned
  • Assignee set to matz (Yukihiro Matsumoto)

Updated by mame (Yusuke Endoh) about 12 years ago

  • Target version set to 2.6
Actions #7

Updated by naruse (Yui NARUSE) almost 7 years ago

  • Target version deleted (2.6)
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0