Deep Copy

I'm needing to implement a deep copy operation on a couple of objects,
and was wondering if there was a "best practices" for this sort of
thing. I've seen the Marshal.load(Marshal.dump()) idiom, but I'm using
singleton classes which can't be dumped. So I'm implementing my deep
copy similar to:

def deep_copy
  other = self.clone
  other.instance_var_1 = self.instance_var_1.clone
  other.instance_var_2 = self.instance_var_2.deep_copy
  other
end

where some of the instance variables are objects for which I've written
a deep_copy method.

The biggest problem with this method (that I can see), is that all of
the attributes of the object need to be publically writable, which is
undesirable. Is there a better way to do this sort of thing?

Thanks,
-Mike

···

--
Posted via http://www.ruby-forum.com/.

I'm needing to implement a deep copy operation on a couple of objects,
and was wondering if there was a "best practices" for this sort of
thing. I've seen the Marshal.load(Marshal.dump()) idiom, but I'm using
singleton classes which can't be dumped.

It seems they can be dumped - but you get another instance:

irb(main):001:0> require 'singleton'
=> true
irb(main):002:0> class Foo
irb(main):003:1> include Singleton
irb(main):004:1> end
=> Foo
irb(main):005:0> Foo.instance
=> #<Foo:0x7ef573a4>
irb(main):006:0> Foo.instance
=> #<Foo:0x7ef573a4>
irb(main):007:0> Marshal.dump(Foo.instance)
=> "\004\bo:\bFoo\000"
irb(main):008:0> Marshal.load(Marshal.dump(Foo.instance))
=> #<Foo:0x10410b08>
irb(main):009:0> Marshal.load(Marshal.dump(Foo.instance)).object_id
=> 1065153200
irb(main):010:0> Foo.instance.object_id
=> 1065007570
irb(main):011:0>

So I'm implementing my deep
copy similar to:

def deep_copy
  other = self.clone
  other.instance_var_1 = self.instance_var_1.clone
  other.instance_var_2 = self.instance_var_2.deep_copy
  other
end

where some of the instance variables are objects for which I've written
a deep_copy method.

The biggest problem with this method (that I can see), is that all of
the attributes of the object need to be publically writable, which is
undesirable. Is there a better way to do this sort of thing?

You can use #instance_variable_get and #instance_variable_set to access them.

Did you consider overriding #dup and / or #clone for this? Typically you would not want a cloned / duped instance to refer to the original instance's instance variables (at least if they are mutable like collections, strings and other objects).

Kind regards

  robert

···

On 05.06.2007 16:45, Michael Artz wrote:

I haven't used this and I'm not sure this is what you want but a deep
copy post recently went through Ruby List.

Take a look.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/43424

http://d.hatena.ne.jp/pegacorn/20070412/1176309956

Harry

···

On 6/5/07, Michael Artz <mlartz@gmail.com> wrote:

I'm needing to implement a deep copy operation on a couple of objects,
and was wondering if there was a "best practices" for this sort of
thing. I've seen the Marshal.load(Marshal.dump()) idiom, but I'm using
singleton classes which can't be dumped. So I'm implementing my deep
copy similar to:

def deep_copy
  other = self.clone
  other.instance_var_1 = self.instance_var_1.clone
  other.instance_var_2 = self.instance_var_2.deep_copy
  other
end

where some of the instance variables are objects for which I've written
a deep_copy method.

The biggest problem with this method (that I can see), is that all of
the attributes of the object need to be publically writable, which is
undesirable. Is there a better way to do this sort of thing?

Thanks,
-Mike

--
Posted via http://www.ruby-forum.com/\.

--

A Look into Japanese Ruby List in English

Robert Klemme wrote:

I'm needing to implement a deep copy operation on a couple of objects,
and was wondering if there was a "best practices" for this sort of
thing. I've seen the Marshal.load(Marshal.dump()) idiom, but I'm using
singleton classes which can't be dumped.

It seems they can be dumped - but you get another instance:

hmm, my classes are structured as:

class A
  class B
    class C
    end
  end
end

... and ...

c = A::b::C.new
Marshal.dump(c)

... seems to work just fine, so I'm not quite sure what is going on with
my code, as I still get a "TypeError: singleton can't be dumped" from
Marshal.dump. I'll have to play around with it a bit more.

You can use #instance_variable_get and #instance_variable_set to access
  them.

Sweet, thanks!

Did you consider overriding #dup and / or #clone for this? Typically
you would not want a cloned / duped instance to refer to the original
instance's instance variables (at least if they are mutable like
collections, strings and other objects).

Yeah, but I can't seem to wrap my head around the recursive cloning.
For example, in the above scenarion (A::b::C), how do I allocate space
for the new object without calling clone/dup? I.e, I'm sure that you
realize the problem with the following:

class A
  class B
    class C
      def clone
        other = self.clone
      end
    end
  end
end

So how do I get the "other" object within the clone method? Do I need
to allow my initialize method to take in an object of the same type and
perform all the work of the clone method, or is there a better way?

Thanks
-Mike

···

On 05.06.2007 16:45, Michael Artz wrote:

--
Posted via http://www.ruby-forum.com/\.

Michael Artz a écrit :

Robert Klemme wrote:
  

I'm needing to implement a deep copy operation on a couple of objects,
and was wondering if there was a "best practices" for this sort of
thing. I've seen the Marshal.load(Marshal.dump()) idiom, but I'm using
singleton classes which can't be dumped.
      

It seems they can be dumped - but you get another instance:
    
hmm, my classes are structured as:

class A
  class B
    class C
    end
  end
end

... and ...

c = A::b::C.new
Marshal.dump(c)

... seems to work just fine, so I'm not quite sure what is going on with my code, as I still get a "TypeError: singleton can't be dumped" from Marshal.dump. I'll have to play around with it a bit more.

You can use #instance_variable_get and #instance_variable_set to access
  them.
    
Sweet, thanks!

Did you consider overriding #dup and / or #clone for this? Typically
you would not want a cloned / duped instance to refer to the original
instance's instance variables (at least if they are mutable like
collections, strings and other objects).
    
Yeah, but I can't seem to wrap my head around the recursive cloning. For example, in the above scenarion (A::b::C), how do I allocate space for the new object without calling clone/dup? I.e, I'm sure that you realize the problem with the following:

class A
  class B
    class C
      def clone
        other = self.clone
      end
    end
  end
end

So how do I get the "other" object within the clone method? Do I need to allow my initialize method to take in an object of the same type and perform all the work of the clone method, or is there a better way?

Thanks
-Mike

Hi,

To clone an object, you should define the #initialize_copy method in your class. This method takes the object to copy from, in argument. It is used by #clone and #dup to perform the initialization of the cloned object.

···

On 05.06.2007 16:45, Michael Artz wrote:

Olivier Renaud wrote:

To clone an object, you should define the #initialize_copy method in
your class.

Perfect, exactly what I need. Thanks!

-Mike

···

--
Posted via http://www.ruby-forum.com/\.