www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - clone method of Object

reply Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
Hi All,

is there any (easy) way to clone an object or any other classes?


--Qian
Apr 15 2009
next sibling parent reply grauzone <none example.net> writes:
Qian Xu wrote:
 Hi All,
 
 is there any (easy) way to clone an object or any other classes?
 
 
 --Qian
Simple answer: No. Complicated answer: Yes, but you have to write it yourself. Here's a nice starting point. You can use tupleof to get all members of a class. Note that this doesn't deal with superclasses, and members of superclasses are not copied: T clone(T)(T old) { auto newobject = new T(); foreach (int i, _; old.tupleof) { newobject.tupleof[i] = old.tupleof[i]; } return newobject; } cloned = clone(yourobject);
Apr 15 2009
next sibling parent reply grauzone <none example.net> writes:
grauzone wrote:
 Qian Xu wrote:
 Hi All,

 is there any (easy) way to clone an object or any other classes?


 --Qian
Simple answer: No. Complicated answer: Yes, but you have to write it yourself. Here's a nice starting point. You can use tupleof to get all members of a class. Note that this doesn't deal with superclasses, and members of superclasses are not copied: T clone(T)(T old) { auto newobject = new T(); foreach (int i, _; old.tupleof) { newobject.tupleof[i] = old.tupleof[i]; } return newobject; } cloned = clone(yourobject);
I should add that members of subclasses are not copied either. E.g. if you have class A {int a;} class B : A {int b;} class C : B {int c;} B someobject; clone(someobject); the clone method will only copy member b, but not a or c.
Apr 15 2009
parent reply bearophile <bearophileHUGS lycos.com> writes:
grauzone:
 the clone method will only copy member b, but not a or c.
A *good* implementation of this function seems fit to be added to Phobos. Bye, bearophile
Apr 15 2009
parent grauzone <none example.net> writes:
bearophile wrote:
 grauzone:
 the clone method will only copy member b, but not a or c.
A *good* implementation of this function seems fit to be added to Phobos.
And serialization, and a complete reflection API.
 Bye,
 bearophile
Apr 15 2009
prev sibling next sibling parent reply Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
grauzone wrote:
 newobject.tupleof[i] = old.tupleof[i];
If the current value of tupleof[i] is an object, the object will be referenced, won't it? Shall I write: auto elem = old.tupleof[i]; static if (is(typeof(elem) == class)) { newobject.tupleof[i] = clone(elem); } else { newobject.tupleof[i] = elem; } --Qian
Apr 15 2009
parent reply grauzone <none example.net> writes:
Qian Xu wrote:
 grauzone wrote:
 newobject.tupleof[i] = old.tupleof[i];
If the current value of tupleof[i] is an object, the object will be referenced, won't it? Shall I write: auto elem = old.tupleof[i]; static if (is(typeof(elem) == class)) { newobject.tupleof[i] = clone(elem); } else { newobject.tupleof[i] = elem; }
Object graphs often contain circular references liker this: class A { B b; } class B { A a; } auto a = new A(); auto b = new B(); a.b = b; b.a = a; Your recursive approach wouldn't quite work with that. Before cloning an object, you'll first have to check if the object was already cloned. If this is the case, use the previously created clone instead of making a new clone.
 
 
 
 --Qian
Apr 15 2009
parent Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
grauzone wrote:

 
 class A {
 B b;
 }
 
 class B {
 A a;
 }
 
 auto a = new A();
 auto b = new B();
 a.b = b;
 b.a = a;
 
 Your recursive approach wouldn't quite work with that. Before cloning an
 object, you'll first have to check if the object was already cloned. If
 this is the case, use the previously created clone instead of making a
 new clone.
You are right. This case must be considered separately.
Apr 15 2009
prev sibling parent reply Qian Xu <quian.xu stud.tu-ilmenau.de> writes:
grauzone wrote:

 ...
 cloned = clone(yourobject);
Hi again. There are two things on my side: 1. Compiler refuses to clone private attributes. I have tried gdc/gdmd/dmd_v1 in Linux. 2. I have implemented an example. But some part not implemented. ----------------- code ----------------------- T clone(T)(T oldobj) { auto newobj = new T(); if (oldobj is null) { return newobj; } foreach (int i, _; oldobj.tupleof) { auto elem = oldobj.tupleof[i]; static if (is(typeof(elem): char[]*)) {/* if (elem !is null) { char[] tmp; tmp = (*elem).dup; newobj.tupleof[i] = &tmp; } else { newobj.tupleof[i] = null; }*/ NotImplemented_PleaseHelpMe; } else static if (is(typeof(elem) T2 : T2*)) { if (elem !is null) { newobj.tupleof[i] = new T2; *newobj.tupleof[i] = *elem; } else { newobj.tupleof[i] = null; } } else static if (is(typeof(elem) == class)) { if (elem !is null) { newobj.tupleof[i] = clone(elem); } else { newobj.tupleof[i] = null; } } else { newobj.tupleof[i] = elem; } } return newobj; } ----------------- code -----------------------
Apr 15 2009
parent grauzone <none example.net> writes:
 There are two things on my side:
 1. Compiler refuses to clone private attributes. I have tried
 gdc/gdmd/dmd_v1 in Linux.
It was changed in dmd later, and now you can access private attributes by using tupleof. I don't know when exactly it was changed, but it should work at least with dmd 1.039 and later. GDC probably uses an ancient front-end version, and I think nobody should use it.
Apr 15 2009
prev sibling parent jDavidls <jdavidls gmail.com> writes:
This works very well (GDC 4.2.4):

Object clone(Object object)
{
	auto size = object.classinfo.init.length;

	object = cast(Object) ( (cast(void*)object) [0..size].dup.ptr );

//	object.__monitor = null;

	return object;
}
Sep 20 2009