Jump to page: 1 2
Thread overview
clone method of Object
Apr 15, 2009
Qian Xu
Apr 15, 2009
grauzone
Apr 15, 2009
grauzone
Apr 15, 2009
bearophile
Apr 15, 2009
grauzone
Apr 15, 2009
Qian Xu
Apr 15, 2009
grauzone
Apr 15, 2009
Qian Xu
Apr 15, 2009
Qian Xu
Apr 15, 2009
grauzone
Sep 21, 2009
jDavidls
April 15, 2009
Hi All,

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


--Qian
April 15, 2009
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);

April 15, 2009
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.
April 15, 2009
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
April 15, 2009
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
April 15, 2009
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 -----------------------

April 15, 2009
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.
April 15, 2009
> 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.
April 15, 2009
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
April 15, 2009
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
« First   ‹ Prev
1 2