www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to copy an object?

reply Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> writes:
I want a shallow copy of an object. Something like:

# Object obj = someOtherObj.copy;

where I could assert afterwards that:
- obj !is someOtherObj
- they have the same class
- their data members are identical

In C# this is called MemberwiseClone (although it's protected so you
have to wrap it with a public method).

In Python, this is done with the copy module.

Is there something analagous in D? (I searched for "copy" and "clone"
in various places like this newsgroup, the Phobos docs and Wiki4D, but
didn't catch anything.)


Thanks,
-Chuck
Aug 19 2005
next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> wrote:

 I want a shallow copy of an object.

Please read the FAQ: Why is overload the assignment operator not supported? -manfred
Aug 19 2005
parent reply Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> writes:
On Sat, 20 Aug 2005 05:26:49 +0000 (UTC), Manfred Nowak
<svv1999 hotmail.com> wrote:

Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> wrote:

 I want a shallow copy of an object.

Please read the FAQ: Why is overload the assignment operator not supported? -manfred

I assume you're referring to: "Sometimes, one does need to create a copy of a class object, and for that one can still write a copy constructor in D" ...as I'm not wanting to redefine =. Let me clarify my question: Is there a general purpose function that is written, or could be written, to take any obj ref and return a copy of it? Something like: Object copy(Object obj) { Object newObj; <insert magic here>; return newObj; } Maybe it would even be something like: Object copy(Object obj) { if (obj is null) return null; int* newObj = cast(int*)malloc(SIZEOF?(obj)); memcpy(newObj, (int*)obj, SIZEOF?(obj)); return cast(Object)newObj; } Or maybe those should be "void*" instead of "int*" above. Also, I don't know how to get the size of any arbitrary object. -Chuck
Aug 20 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in message 
news:ji7eg1h3sagap5atgtmufu4uinc6q1kll2 4ax.com...
 On Sat, 20 Aug 2005 05:26:49 +0000 (UTC), Manfred Nowak
 <svv1999 hotmail.com> wrote:

Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> wrote:

 I want a shallow copy of an object.

Please read the FAQ: Why is overload the assignment operator not supported? -manfred

I assume you're referring to: "Sometimes, one does need to create a copy of a class object, and for that one can still write a copy constructor in D" ...as I'm not wanting to redefine =. Let me clarify my question: Is there a general purpose function that is written, or could be written, to take any obj ref and return a copy of it?

Nope. If a class authors wants a class to be copyable they need to write either a dup() property or a copy constructor. Technically they can write whatever function they want but dup() is the standard name for the "duplicate" method. What are you trying to do?
 Something like:

 Object copy(Object obj) {
    Object newObj;
    <insert magic here>;
    return newObj;
 }

 Maybe it would even be something like:

 Object copy(Object obj) {
    if (obj is null)
        return null;
    int* newObj = cast(int*)malloc(SIZEOF?(obj));
    memcpy(newObj, (int*)obj, SIZEOF?(obj));
    return cast(Object)newObj;
 }

 Or maybe those should be "void*" instead of "int*" above. Also, I
 don't know how to get the size of any arbitrary object.

 -Chuck 

Aug 20 2005
parent Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> writes:
On Sat, 20 Aug 2005 08:46:59 -0400, "Ben Hinkle"
<ben.hinkle gmail.com> wrote:
"Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in message 

 Is there a general purpose function that is written, or could be
 written, to take any obj ref and return a copy of it?

Nope. If a class authors wants a class to be copyable they need to write either a dup() property or a copy constructor. Technically they can write whatever function they want but dup() is the standard name for the "duplicate" method. What are you trying to do?

It would be nice to have this feature to reduce maintenance so that if I add a member var "int _foo;" I don't get burned by forgetting to update dup(). Also, I'm exploring the language and I'm used to having a "shallow copy" function in languages such as C#, Python and Smalltalk. So it's one of those things I happen to look for. Thanks for the reply, -Chuck
Aug 20 2005
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in message 
news:ji7eg1h3sagap5atgtmufu4uinc6q1kll2 4ax.com...
 Or maybe those should be "void*" instead of "int*" above. Also, I
 don't know how to get the size of any arbitrary object.

It's typename.sizeof in D. Like int.sizeof or MyClass.sizeof.
Aug 20 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Jarrett Billingsley wrote:

 "Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in message 
 news:ji7eg1h3sagap5atgtmufu4uinc6q1kll2 4ax.com...
 
Or maybe those should be "void*" instead of "int*" above. Also, I
don't know how to get the size of any arbitrary object.

It's typename.sizeof in D. Like int.sizeof or MyClass.sizeof.

sizeof returns the size of the value on the stack, so a class's sizeof is always 4.
Aug 20 2005
parent Chris Sauls <ibisbasenji gmail.com> writes:
Burton Radons wrote:
 Jarrett Billingsley wrote:
 
 "Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in 
 message news:ji7eg1h3sagap5atgtmufu4uinc6q1kll2 4ax.com...

 Or maybe those should be "void*" instead of "int*" above. Also, I
 don't know how to get the size of any arbitrary object.

It's typename.sizeof in D. Like int.sizeof or MyClass.sizeof.

sizeof returns the size of the value on the stack, so a class's sizeof is always 4.

Would .classinfo.init.size work? -- Chris Sauls
Aug 20 2005
prev sibling parent reply Burton Radons <burton-radons smocky.com> writes:
Chuck Esterbrook wrote:

 I want a shallow copy of an object. Something like:
 
 # Object obj = someOtherObj.copy;
 
 where I could assert afterwards that:
 - obj !is someOtherObj
 - they have the same class
 - their data members are identical
 
 In C# this is called MemberwiseClone (although it's protected so you
 have to wrap it with a public method).
 
 In Python, this is done with the copy module.
 
 Is there something analagous in D? (I searched for "copy" and "clone"
 in various places like this newsgroup, the Phobos docs and Wiki4D, but
 didn't catch anything.)

extern (C) Object _d_newclass (ClassInfo info); template shallow_copy (T : Object) { T shallow_copy (T value) { if (value is null) return null; void *copy = _d_newclass (value.classinfo); size_t size = value.classinfo.init.length; copy [0 .. size] = (cast (void *) value) [0 .. size]; return cast (T) copy; } } :Q
Aug 20 2005
parent reply Burton Radons <burton-radons smocky.com> writes:
Haha, why'd I put that in a template?  It just hides the cast.  That 
should be:

     private extern (C) Object _d_newclass (ClassInfo info);

     Object shallow_copy (Object value)
     {
         if (value is null)
             return null;

         void *copy = _d_newclass (value.classinfo);
         size_t size = value.classinfo.init.length;

         copy [8 .. size] = (cast (void *) value) [8 .. size];
         return cast (Object) copy;
     }

Better to start at that offset to avoid copying the synchronisation 
handle over, plus it's pointless work.
Aug 20 2005
next sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Burton Radons" <burton-radons smocky.com> wrote in message 
news:de838k$1ouu$1 digitaldaemon.com...
 Haha, why'd I put that in a template?  It just hides the cast.  That 
 should be:

     private extern (C) Object _d_newclass (ClassInfo info);

     Object shallow_copy (Object value)
     {
         if (value is null)
             return null;

         void *copy = _d_newclass (value.classinfo);
         size_t size = value.classinfo.init.length;

         copy [8 .. size] = (cast (void *) value) [8 .. size];
         return cast (Object) copy;
     }

 Better to start at that offset to avoid copying the synchronisation handle 
 over, plus it's pointless work.

It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like /** Clobbers an object with the contents of another object of the same * class. Clobbering an arbitrary object is very risky so only use the * function inside of a dup() method in a class after creating the * target duplicate. For example, * class Foo { * int test; * int some_other_state; * this(int t) { test = t; } * Foo dup() { * Foo res = new Foo(test); * clobber(res, this); * return res; * } * } * ... * Foo x = new Foo(10); * ... * Foo y = x.dup; */ void clobber(Object dest, Object source) { ClassInfo ci = source.classinfo; if (ci !is dest.classinfo) throw new Exception("Cannot clobber subclasses or superclasses"); void* s = source; void* d = dest; size_t start = Object.classinfo.init.length; d[start .. ci.init.length] = s[start .. ci.init.length]; }
Aug 20 2005
parent reply Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> writes:
On Sat, 20 Aug 2005 19:21:17 -0400, "Ben Hinkle"
<ben.hinkle gmail.com> wrote:

"Burton Radons" <burton-radons smocky.com> wrote in message 
news:de838k$1ouu$1 digitaldaemon.com...
 Haha, why'd I put that in a template?  It just hides the cast.  That 
 should be:

     private extern (C) Object _d_newclass (ClassInfo info);

     Object shallow_copy (Object value)
     {
         if (value is null)
             return null;

         void *copy = _d_newclass (value.classinfo);
         size_t size = value.classinfo.init.length;

         copy [8 .. size] = (cast (void *) value) [8 .. size];
         return cast (Object) copy;
     }

 Better to start at that offset to avoid copying the synchronisation handle 
 over, plus it's pointless work.

It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like /** Clobbers an object with the contents of another object of the same * class. Clobbering an arbitrary object is very risky so only use the * function inside of a dup() method in a class after creating the * target duplicate. For example, * class Foo { * int test; * int some_other_state; * this(int t) { test = t; } * Foo dup() { * Foo res = new Foo(test); * clobber(res, this); * return res; * } * } * ... * Foo x = new Foo(10); * ... * Foo y = x.dup; */ void clobber(Object dest, Object source) { ClassInfo ci = source.classinfo; if (ci !is dest.classinfo) throw new Exception("Cannot clobber subclasses or superclasses"); void* s = source; void* d = dest; size_t start = Object.classinfo.init.length; d[start .. ci.init.length] = s[start .. ci.init.length]; }

Doesn't bar.dup() fail for a subclass Bar of Foo? Unless I reimplement it, of course. -Chuck
Aug 20 2005
parent "Ben Hinkle" <ben.hinkle gmail.com> writes:
"Chuck Esterbrook" <Chuck.Esterbrook gmail.antispam.com> wrote in message 
news:3eifg1h5rbi03ql7etpur7i8645kumptet 4ax.com...
 On Sat, 20 Aug 2005 19:21:17 -0400, "Ben Hinkle"
 <ben.hinkle gmail.com> wrote:

"Burton Radons" <burton-radons smocky.com> wrote in message
news:de838k$1ouu$1 digitaldaemon.com...
 Haha, why'd I put that in a template?  It just hides the cast.  That
 should be:

     private extern (C) Object _d_newclass (ClassInfo info);

     Object shallow_copy (Object value)
     {
         if (value is null)
             return null;

         void *copy = _d_newclass (value.classinfo);
         size_t size = value.classinfo.init.length;

         copy [8 .. size] = (cast (void *) value) [8 .. size];
         return cast (Object) copy;
     }

 Better to start at that offset to avoid copying the synchronisation 
 handle
 over, plus it's pointless work.

It's too bad it depends on a compiler-specific function (_d_newclass) and doesn't allow classes to say they don't want to be shallow_copied because they have a custom allocator or constructor behavior. Something slightly less risky would be something like /** Clobbers an object with the contents of another object of the same * class. Clobbering an arbitrary object is very risky so only use the * function inside of a dup() method in a class after creating the * target duplicate. For example, * class Foo { * int test; * int some_other_state; * this(int t) { test = t; } * Foo dup() { * Foo res = new Foo(test); * clobber(res, this); * return res; * } * } * ... * Foo x = new Foo(10); * ... * Foo y = x.dup; */ void clobber(Object dest, Object source) { ClassInfo ci = source.classinfo; if (ci !is dest.classinfo) throw new Exception("Cannot clobber subclasses or superclasses"); void* s = source; void* d = dest; size_t start = Object.classinfo.init.length; d[start .. ci.init.length] = s[start .. ci.init.length]; }

Doesn't bar.dup() fail for a subclass Bar of Foo? Unless I reimplement it, of course. -Chuck

Yeah. That's on purpose - I'd like subclasses to always say how they dup just like they say how they are constructed. One can call _d_newclass and clobber that if you want to let subclasses inherit dup "silently". For classes that can be subclassed I'd probably go with using clobber in a copy constructor instead of inside dup, actually: class Foo { this(Foo obj) { clobber(this,obj); } ... } Then there's no confusion about dup having to be overriden by the subclass.
Aug 20 2005
prev sibling parent Chuck Esterbrook <Chuck.Esterbrook gmail.antispam.com> writes:
On Sat, 20 Aug 2005 13:19:41 -0700, Burton Radons
<burton-radons smocky.com> wrote:

Haha, why'd I put that in a template?  It just hides the cast.  That 
should be:

     private extern (C) Object _d_newclass (ClassInfo info);

     Object shallow_copy (Object value)
     {
         if (value is null)
             return null;

         void *copy = _d_newclass (value.classinfo);
         size_t size = value.classinfo.init.length;

         copy [8 .. size] = (cast (void *) value) [8 .. size];
         return cast (Object) copy;
     }

Better to start at that offset to avoid copying the synchronisation 
handle over, plus it's pointless work.

Thanks, Burton. That's pretty neat. I had figured out the "value.classinfo.init.length", but not the _d_newclass. As Ben points out, it won't work with custom allocators, but since I'm using any in my own classes, that's fine. -Chuck
Aug 20 2005