Deep copy in Rub?

I remember when using C++ for the first time and running into the shallow/deep
copy problem. “I copied my object, freed something in obj_b, but it’s also gone
in obj_a, what gives!?!” :slight_smile:

I’m a Ruby Newbie now and wonder how this issue is addressed in Ruby. I’ve seen
references to a clone() method, is this related?

Can anyone enlighten me on this topic with respect to Ruby? :slight_smile:

Thanks very much!
Christopher

Christopher J. Meisenzahl CPS, CSTE
Senior Software Testing Consultant
Spherion
christopher.j.meisenzahl@citicorp.com

christopher.j.meisenzahl@citicorp.com wrote in message
news:H00019f009c894c4@MHS…

I remember when using C++ for the first time and running into the
shallow/deep
copy problem. “I copied my object, freed something in obj_b, but it’s also
gone
in obj_a, what gives!?!” :slight_smile:

I’m a Ruby Newbie now and wonder how this issue is addressed in Ruby. I’ve
seen
references to a clone() method, is this related?

Someone here knows more about this than I and I’ve never really worked with
deep copy, anyway …

clone is a flat copy.
In Ruby, any value deep or flat, integer or complex object, is stored in an
object as a reference.
All references are simply copied using clone, not the content of the
references. Not what you want.

The marshal interface serializes an object to string, including references.
A deep copy can be made using marshal, search google groups for marshal and
copy. There are limitations to using marshal - there could be circular
references and you could be referencing too much data.

Are you really sure you need deep copy?
In all the time I’ve developed software I haven’t needed deep copy ever,
although it is some of those things you initially wonder about.
I’d claim the need for deep copy indicates a design problem except for a few
cases:

  1. Object creation by prototyping - for example copying drawings in a
    drawing program
  2. Remote object creation in distributed computing (see marshal, drb).

Actually there was a pretty ugly deep copy bug related to 1) in an early
Ration Rose version. Delete one of the carefully designed boxes, and all the
copies disappeared like magic.

Mikkel

christopher.j.meisenzahl@citicorp.com writes:

I remember when using C++ for the first time and running into the
shallow/deep copy problem. “I copied my object, freed something in
obj_b, but it’s also gone in obj_a, what gives!?!” :slight_smile:

In addition to the other answers, there are two methods to copy an
object in Ruby. Object.dup and Object.clone.

I’m not sure why – they don’t do anything different in the standard
classes. The Pickaxe book says they might do something different in
derived classes, but stops short of suggesting a practice (e.g. clone
does deep copy and dup does shallow copy).

“MikkelFJ” mikkelfj-anti-spam@bigfoot.com writes:

clone is a flat copy.
In Ruby, any value deep or flat, integer or complex object, is stored in an
object as a reference.

It doesn’t make sense to say a value is flat or deep.

All references are simply copied using clone, not the content of the
references. Not what you want.

When you do #clone, it really makes a duplicate of the object. The
difference between a ‘shallow copy’ versus a ‘deep copy’ is the extent
of the duplication. A shallow copy will only duplicate the #clone’d
object. A deep copy duplicates the #clone’d object and recursively
#clone all objects that it referes to.

Are you really sure you need deep copy?

There are some valid usages, a few, not many.

The easiest way to do deep copy is by using module Marshall:

require ‘marshal’
a_copy = Marshal.load(Marshal.dump(the_original_object))

The pickaxe book has a more detailed documentation of this module.

YS.

Matt Armstrong wrote:

In addition to the other answers, there are two methods to copy an
object in Ruby. Object.dup and Object.clone.

I’m not sure why – they don’t do anything different in the standard
classes. The Pickaxe book says they might do something different in
derived classes, but stops short of suggesting a practice (e.g. clone
does deep copy and dup does shallow copy).

There are differences:

[kentda@v052a kentda]$ irb
irb(main):001:0> a = “Hi”
“Hi”
irb(main):002:0> a.freeze
“Hi”
irb(main):003:0> a.dup.frozen?
false
irb(main):004:0> a.clone.frozen?
true

···


([ Kent Dahl ]/)_ ~ [ http://www.stud.ntnu.no/~kentda/ ]/~
))_student
/(( _d L b_/ NTNU - graduate engineering - 5. year )
( __õ|õ// ) )Industrial economics and technological management(
_
/ö____/ (_engineering.discipline=Computer::Technology)

Hello Kent,

Tuesday, December 17, 2002, 11:25:00 AM, you wrote:

I’m not sure why – they don’t do anything different in the standard
classes. The Pickaxe book says they might do something different in
derived classes, but stops short of suggesting a practice (e.g. clone
does deep copy and dup does shallow copy).

anyone can tell why ruby don’t have deep copy routine in standard distribution?

···


Best regards,
Bulat mailto:bulatz@integ.ru

“Bulat Ziganshin” bulatz@integ.ru writes:

Hello Kent,

Tuesday, December 17, 2002, 11:25:00 AM, you wrote:

I’m not sure why – they don’t do anything different in the standard
classes. The Pickaxe book says they might do something different in
derived classes, but stops short of suggesting a practice (e.g. clone
does deep copy and dup does shallow copy).

anyone can tell why ruby don’t have deep copy routine in standard distribution?

But it has. Didn’t you read my post?

YS.

My Ruby has it now:

flori@lambda flori$ irb --prompt xmp
VERSION
==>“1.7.3”
o = [“foo”]
==>[“foo”]
oc = o.deep_clone
==>[“foo”]
o[0].equal? oc[0]
==>false

···

On 2002-12-18 01:20:18 +0900, Yohanes Santoso wrote:

anyone can tell why ruby don’t have deep copy routine in standard
distribution?
But it has. Didn’t you read my post?


Men are born ignorant, not stupid. They are made stupid by education.
– Bertand Russell

I just did a CVS get this morning…

irb(main):001:0> VERSION
=> “1.7.3”
irb(main):002:0> a=%w{a b c}
=> [“a”, “b”, “c”]
irb(main):003:0> b=a.deep_clone
NoMethodError: undefined method `deep_clone’ for [“a”, “b”, “c”]:Array
from (irb):3

···

On Wednesday, 18 December 2002 at 1:50:11 +0900, Florian Frank wrote:

On 2002-12-18 01:20:18 +0900, Yohanes Santoso wrote:

anyone can tell why ruby don’t have deep copy routine in standard
distribution?
But it has. Didn’t you read my post?

My Ruby has it now:

flori@lambda flori$ irb --prompt xmp
VERSION
==>“1.7.3”
o = [“foo”]
==>[“foo”]
oc = o.deep_clone
==>[“foo”]
o[0].equal? oc[0]
==>false


Jim Freeze

Executive ability is deciding quickly and getting somebody else to do
the work.
– John G. Pollard

OK. The only problem is that I can’t commit my patches there. :wink:

flori@lambda ruby$ cvs diff object.c
Index: object.c

···

On 2002-12-18 01:53:47 +0900, Jim Freeze wrote:

My Ruby has it now:

flori@lambda flori$ irb --prompt xmp
VERSION
==>“1.7.3”
o = [“foo”]
==>[“foo”]
oc = o.deep_clone
==>[“foo”]
o[0].equal? oc[0]
==>false
I just did a CVS get this morning…

===================================================================
RCS file: /src/ruby/object.c,v
retrieving revision 1.96
diff -p -u -r1.96 object.c
— object.c 10 Dec 2002 06:23:40 -0000 1.96
+++ object.c 17 Dec 2002 17:34:51 -0000
@@ -152,6 +152,21 @@ rb_obj_clone(obj)
}

VALUE
+rb_obj_deep_clone(obj)

  • VALUE obj;
    +{
  • VALUE clone;
  • if (rb_special_const_p(obj)) {
  •    rb_raise(rb_eTypeError, "can't clone %s",
    

rb_class2name(CLASS_OF(obj)));

  • }
  • clone = rb_marshal_load(rb_marshal_dump(obj, Qnil));
  • RBASIC(clone)->flags = RBASIC(obj)->flags | FL_TEST(clone,
    FL_TAINT);
  • return clone;
    +}

+VALUE
rb_obj_dup(obj)
VALUE obj;
{
@@ -1332,6 +1347,7 @@ Init_Object()
rb_define_method(rb_mKernel, “class”, rb_obj_class, 0);

 rb_define_method(rb_mKernel, "clone", rb_obj_clone, 0);
  • rb_define_method(rb_mKernel, “deep_clone”, rb_obj_deep_clone, 0);
    rb_define_method(rb_mKernel, “dup”, rb_obj_dup, 0);
    rb_define_method(rb_mKernel, “copy_object”, rb_obj_copy_object, 1);

The only problem is that marshal doesn’t copy the frozen flags for the
clone. If it would it could be possible to have “deep_clone” and
“deep_dup”.


Most people would rather die than think; in fact, they do so.
– Bertand Russell

“Florian Frank” flori@nixe.ping.de wrote in > The only problem is that
marshal doesn’t copy the frozen flags for the

clone. If it would it could be possible to have “deep_clone” and
“deep_dup”.

There are other rather serious draw backs with the ``dump -load scheme’':

For example, you (normally) cannot dump ``data-structures" involving

singleton objects down the road. The (IMO) best|correct solution would

would be the introduction of an ``object-walker" scheme providing a unified

basis for both Marshalling and deep-copying functionality - check out …

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/34343

/Christoph