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
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
> 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.
> 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).
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___)
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
> 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](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
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
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
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