July 14, 2004
Florian RIVOAL wrote:

>>> If need be, clone()/.dup() can then be overridden to return anything the implementor wants: this, null, an uninitalized struct/class, or even throw an exception if the operation is not allowed.
>> 
>> I don't see any point in making this a disallowed operation.  If copying the object doesn't make sense for whatever class, we might as well copy the reference instead.
> 
> Not sure either, but ask the guys at working for sun, they might have an idea, since java includes this behaviour : it throws an exception if you try to clone something without explicit mention it is clonable.

Java has the Cloneable interface.  The default behaviour of objects that implement Cloneable is a shallow memberwise copy.  Classes are allowed to override clone pretty much how they like.  However, with Java data structures tending to accommodate arbitrary objects, you can't guarantee non-circularity.  If you could, a typical behaviour would perhaps be to see if each element instanceof Cloneable, and if so then clone it, otherwise copy the reference.

That's indeed what would happen with behaviour (c) I suggested.  D is a different kettle of fish, as it has templates* and so little need to declare data structures taking arbitrary combinations of objects.  But still, there is some caution to be taken.

*OK, so Java has recently added them so I've heard, but plenty of legacy code is around using the Object structures....

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment.  Please keep replies on the 'group where everyone may benefit.
July 14, 2004
In article <cd2v1k$14m1$1@digitaldaemon.com>, Stewart Gordon says...
>
>pragma <EricAnderton at yahoo dot com> wrote:
><snip>
>> The best compromise would be something like (C): to have Object.clone default to a shallow copy, much like .dup() does for arrays. Actually, .dup() should probably be used for objects too for language consistency.
>
>Actually, we should be careful to distinguish between .dup (a shallow copy, by definition) and .clone (a deep copy, or as deep as allowed). But yes, clone would _default_ to a shallow copy at the most.
>
>If we're going to have shallow object copies as a default behaviour, then we might as well define it in Object.dup, and have Object.clone simply call this method.  We'd need clear documentation of the contractual difference between them.

I see what you're saying by wanting to have mulitple ways to manipulate object cloning.  It makes sense to have multiple methods for multiple needs (.dup vs clone).

My question is: what would be the major differences/pros/cons between having dup and .clone defined side-by-side in Object instead of just having one or the other?  If a class implementor were to just override the given method to give the behavior they want, then that's less trouble right?

> class MySingleton{
>     static MySingleton _instance;
>     static this(){
>         _instance = new MySingleton();
>     }
>     // override one method to get the job done!
>     void* opDup(){
>         // side-step duplication by returning the instance instead
>         return _instance;
>     }
> }

('opDup' is contrived of course.. it could easily be 'dup' or something else)

If there are fewer places where a given behavior exists, then it should be easier to maintain and hence less buggy.  If the behavior of .dup and .clone are nearly identical, then maybe its better for bug control to make them the same method.  IMO, if someone needs a more specialized kind of copying mechanism, then that should go in a specialised interface/class instead of on "Object"... especially if everyone else isn't going to need it.

>> If need be, clone()/.dup() can then be overridden to return anything the implementor wants: this, null, an uninitalized struct/class, or even throw an exception if the operation is not allowed.
>
>I don't see any point in making this a disallowed operation.  If copying the object doesn't make sense for whatever class, we might as well copy the reference instead.

I agree that returing 'this' or a reference is probably the best default behavior possible.

When I said "event throw an exception..." I was just thinking aloud with some examples of how overriding duplicate/clone freely would give a developer all the flexibility they needed.  In my example above (MySingleton), I could just as easily put an 'assert' or 'throw' in there to prevent an *attempt* in duplication as to discourage its use completely... but that's just an example.

I'm really glad this topic came along.  C++ handles this kind of thing poorly and Java does a little better with use of ICloneable.  Since duplication in D is built-into all the primitive types (arrays), why not make it a standard feature of objects and structs?  Makes sense to me.

- Pragma


July 14, 2004
pragma <EricAnderton at yahoo dot com> wrote:
<snip>
>>     // override one method to get the job done!
>>     void* opDup(){         // side-step duplication by returning the instance instead
>>         return _instance;     }
>> }
> 
> ('opDup' is contrived of course.. it could easily be 'dup' or
> something else)

If arrays are anything to go by, then the 'standard' name already is dup, and it returns an object of the same type, not a void*.

> If there are fewer places where a given behavior exists, then it should be easier to maintain and hence less buggy.

I see little room for bugs in a function like

    Object clone() { return dup(); }

> If the behavior of .dup and .clone are nearly identical, then maybe its better for bug control to make them the same method.

Any half-decent compiler would inline the above so that they become the same method.

<snip>
>> I don't see any point in making this a disallowed operation.  If copying the object doesn't make sense for whatever class, we might as well copy the reference instead.
> 
> I agree that returing 'this' or a reference is probably the best default behavior possible.
<snip>

this already is a reference.  What other kind of reference would we return?

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the
unfortunate victim of intensive mail-bombing at the moment.  Please keep
replies on the 'group where everyone may benefit.
July 14, 2004
In article <cd3jb9$26j4$1@digitaldaemon.com>, Stewart Gordon says...
>
>> If there are fewer places where a given behavior exists, then it should be easier to maintain and hence less buggy.
>
>I see little room for bugs in a function like
>
>     Object clone() { return dup(); }

True enough.  But now we really have two methods for the same basic operation by default.  That doesn't seem useful to me.  I suppose if clone were the only one of the two that is overridable that would be better, but then you still cannot stop clones from being generated through dup.  One point of access solves more problems than two, IMO.

>> If the behavior of .dup and .clone are nearly identical, then maybe its better for bug control to make them the same method.
>
>Any half-decent compiler would inline the above so that they become the same method.

Accept if the're overridable, in which case you're looking into the v-table and cannot optimize it away.

>
><snip>
>>> I don't see any point in making this a disallowed operation.  If copying the object doesn't make sense for whatever class, we might as well copy the reference instead.
>> 
>> I agree that returing 'this' or a reference is probably the best default behavior possible.
><snip>
>
>this already is a reference.  What other kind of reference would we return?

Oops, should've checked that one before hitting 'post'...  you're right, it would be just plain 'ol 'this' by default as you suggested. :)

- Pragma


July 14, 2004
Florian RIVOAL wrote:

> hummm... I wonder if this is already available and i just didn't see what's the
> correct syntax to do it, or if it is just plain missing.
> 
> since all object are held by reference, there might be some times when you want
> to copy them. And if the object it self holds references to other object, in
> depth copy could be usefull. While there is no special difficulty to do it case
> by case, it seems to me there is no general way to do it. As i see it, the
> following stuff would be usefull:
> 
> * a "Object clone()" method in the Object class.
> * a .clone property on arrays, behaving like this :
> - indentical to .dup for arrays of basic types
> - call .clone on all elements for array of array
> - call clone() on all elements for arrays of objects
> 
> So is it there already under a different form?
> if not, is there a good reason why it is not there?

erg.  The problem is that subtracting behaviours from classes doesn't work.  The best you can get is to do what Java does and throw an exception when some "un-inherited" method is called.

Second, loading more stuff into the Object class means loading more baggage into every object created anywhere, even if all it ever does is throw an AssertionFailure.

 -- andy
July 14, 2004
pragma <EricAnderton at yahoo dot com> wrote:

<snip>
> True enough.  But now we really have two methods for the same basic operation by default.  That doesn't seem useful to me.  I suppose if clone were the only one of the two that is overridable that would be better, but then you still cannot stop clones from being generated through dup.  One point of access solves more problems than two, IMO.

The point is that it enables a class to support two kinds of copy: deep and shallow.  The call to dup serves as a point at which the depth will stop, perhaps because that's where non-circularity can no longer be guaranteed, or because you reach a point at which no further depth can possibly exist.

A class that serves as a data structure can override dup in order to create a copy of the whole structure, but not clone the individual elements.  OTOH, it could override clone enabling the individual elements to be cloned as well.  Giving the class user the choice is a possible generic programming advantage.

<snip>
> Accept

Pardon?

> if the're overridable, in which case you're looking into the v-table and cannot optimize it away.
<snip>

It can if the compiler determines that it isn't overridden anywhere below the type in which it is called.

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the
unfortunate victim of intensive mail-bombing at the moment.  Please keep
replies on the 'group where everyone may benefit.
July 14, 2004
In article <cd3oqo$2g0j$1@digitaldaemon.com>, Stewart Gordon says...
>The point is that it enables a class to support two kinds of copy: deep and shallow.  The call to dup serves as a point at which the depth will stop, perhaps because that's where non-circularity can no longer be guaranteed, or because you reach a point at which no further depth can possibly exist.
>
>A class that serves as a data structure can override dup in order to create a copy of the whole structure, but not clone the individual elements.  OTOH, it could override clone enabling the individual elements to be cloned as well.  Giving the class user the choice is a possible generic programming advantage.

Stewart,
I'm glad you put it this way, as I think I understand now. And you're right: it
does give a lot of flexibility when the differences between .dup and .clone are
well-defined.  I'm going to stick to my own opinion on this one, but I *do* see
the merit in this design.  They just don't feel orthogonal enough to me.

Perhaps there's a compromise waiting for us down the road? :)

><snip>
>> Accept
>
>Pardon?

::shrug:: I have no idea.  Is it time for me to reinstall win2k already? ;)

>> if the're overridable, in which case you're looking into the v-table and cannot optimize it away.
><snip>
>
>It can if the compiler determines that it isn't overridden anywhere below the type in which it is called.

Do you mean if the compiler knows if a given class is subclassed anywhere? I don't think that's possible.

- Pragma


July 15, 2004
On Wed, 14 Jul 2004 10:40:03 +0100, Stewart Gordon <smjg_1998@yahoo.com> wrote:
> pragma <EricAnderton at yahoo dot com> wrote:
> <snip>
>> The best compromise would be something like (C): to have Object.clone default to a shallow copy, much like .dup() does for arrays.  Actually, .dup() should probably be used for objects too for language consistency.
>
> Actually, we should be careful to distinguish between .dup (a shallow copy, by definition) and .clone (a deep copy, or as deep as allowed). But yes, clone would _default_ to a shallow copy at the most.
>
> If we're going to have shallow object copies as a default behaviour, then we might as well define it in Object.dup, and have Object.clone simply call this method.  We'd need clear documentation of the contractual difference between them.
>
>> If need be, clone()/.dup() can then be overridden to return anything the implementor wants: this, null, an uninitalized struct/class, or even throw an exception if the operation is not allowed.
>
> I don't see any point in making this a disallowed operation.  If copying the object doesn't make sense for whatever class, we might as well copy the reference instead.

Isn't dup a deep copy currently?
eg.

char[] p = "regan";
char[] s;

s = p     //shallow copy p and s refer to same data
s = p.dup //deep copy, p and s refer to different data

assuming this, then when you write a struct or class you can simply define a 'dup' member and get both shallow and deep copying, right?

import std.c.stdlib;

extern (C)
{
  void *memcpy( void *dest, void *src, size_t count);
}

struct A
{
  void* pdata = null;
  uint plen = 0;

  void set(char[] _data)
  {
    *this = A.init;
    if (!(_data is null)) {
      pdata = cast(void*)_data;
      plen = _data.length;
    }
  }

  A dup()
  {
    A a;
    a.pdata = malloc(plen);
    memcpy(a.pdata,pdata,plen);
    return a;
  }
}

class B
{
  A a;

  this(char[] _a = null)
  {
    a.set(_a);
  }

  B dup()
  {
    B b = new B();
    b.a = a.dup;
    return b;
  }
}

void main()
{
  char[] data = "regan";
  A aa;
  A ab;
  B ba = new B(data);
  B bb = new B();

  aa.set(data);
  ab = aa;      //shallow copy
  printf("A %08x %08x\n",aa.pdata,ab.pdata);
  ab = aa.dup;  //deep copy
  printf("A %08x %08x\n",aa.pdata,ab.pdata);

  bb = ba;      //shallow copy
  printf("B %08x %08x\n",ba.a.pdata,bb.a.pdata);
  bb = ba.dup;  //deep copy
  printf("B %08x %08x\n",ba.a.pdata,bb.a.pdata);
}

Object could have a default dup' method that asserted or threw an exception.
Basic types i.e. int could have a dup method added to them that simply returned themselves.

Thus for any object you could call the dup method to do a deep copy, and for any object you could do a shallow copy simply by assigning it.

Regan.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
July 16, 2004
>The point is that it enables a class to support two kinds of copy: deep and shallow.  The call to dup serves as a point at which the depth will stop, perhaps because that's where non-circularity can no longer be guaranteed, or because you reach a point at which no further depth can possibly exist.
>
>A class that serves as a data structure can override dup in order to create a copy of the whole structure, but not clone the individual elements.  OTOH, it could override clone enabling the individual elements to be cloned as well.  Giving the class user the choice is a possible generic programming advantage.

I totaly agree with this way of doing things. I already can't wait to see it implemented. But i am skipping some steps. Before thinking of seeing added to D, it seems quite reasonable to ask Walter what he thinks about this matter.

So, Walter, any opinion on .dup, .clone and the like?



July 16, 2004
pragma <EricAnderton at yahoo dot com> wrote:

<snip>
>>> if the're overridable, in which case you're looking into the v-table and cannot optimize it away.
>>
>> <snip>
>>
>> It can if the compiler determines that it isn't overridden anywhere below the type in which it is called.
> 
> Do you mean if the compiler knows if a given class is subclassed anywhere? I
> don't think that's possible.

Of course it can.  Look at the class hierarchy to see if there are any subclasses, and then to see if any of them can ever be instantiated in the course of the program.

This is one of the optimisation principles on which D was designed.  See

http://www.digitalmars.com/d/function.html

However, it does require the modules to be compiled all in one go....

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment.  Please keep replies on the 'group where everyone may benefit.