Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Deep copy in Rub?

47 views
Skip to first unread message

christopher....@citicorp.com

unread,
Dec 16, 2002, 1:59:35 PM12/16/02
to

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!?!" :-)

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? :-)

Thanks very much!
Christopher

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


MikkelFJ

unread,
Dec 16, 2002, 3:00:46 PM12/16/02
to

<christopher....@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!?!" :-)
>
> 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

Yohanes Santoso

unread,
Dec 16, 2002, 4:38:42 PM12/16/02
to
"MikkelFJ" <mikkelfj-...@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

unread,
Dec 16, 2002, 4:51:13 PM12/16/02
to
christopher....@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!?!" :-)

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).

Kent Dahl

unread,
Dec 17, 2002, 3:15:06 AM12/17/02
to
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___)

Bulat Ziganshin

unread,
Dec 17, 2002, 3:42:27 AM12/17/02
to
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:bul...@integ.ru

Yohanes Santoso

unread,
Dec 17, 2002, 11:20:18 AM12/17/02
to
"Bulat Ziganshin" <bul...@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.

Florian Frank

unread,
Dec 17, 2002, 11:50:11 AM12/17/02
to
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](0)$ irb --prompt xmp
VERSION
==>"1.7.3"
o = ["foo"]
==>["foo"]
oc = o.deep_clone
==>["foo"]
o[0].equal? oc[0]
==>false

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

Jim Freeze

unread,
Dec 17, 2002, 11:53:47 AM12/17/02
to
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](0)$ 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...

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


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

Florian Frank

unread,
Dec 17, 2002, 12:43:56 PM12/17/02
to
On 2002-12-18 01:53:47 +0900, Jim Freeze wrote:
> > My Ruby has it now:
> >
> > [flori@lambda flori](0)$ 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...

OK. The only problem is that I can't commit my patches there. ;)

[flori@lambda ruby](0)$ cvs diff object.c
Index: object.c
===================================================================
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

Christoph

unread,
Dec 17, 2002, 4:47:45 PM12/17/02
to

"Florian Frank" <fl...@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


0 new messages