www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Taking a copy of an object

reply Derek Parnell <derek nomail.afraid.org> writes:
Currently there doesn't seem to be any standard D mechanism (read:
operator) to take a copy of an object. So are there any suggestions for a
name that we can all agree on; one that might become an unofficial
standard? 

For arrays we have the 'dup' property but for objects there is nothing that
the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
'onDeepCopy' as an additional function.

Example:

  class Foo
  {
      int x;
      Bar b;

      this(int y) 
      {
           x = y;
           b = new Bar(y);
      }

      Foo onCopy()
      {
          Foo t;
          t = new Foo(x);
          return t;
       }
   }

   . . . 

   auto backup = q.onCopy();

And maybe one day (hoping against precedent) that Walter will actually see
that an operator for copying stuff is not such a stupid idea.

   auto backup := q; // invokes q.onCopy() if it exists.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
3/08/2006 5:26:23 PM
Aug 03 2006
next sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Derek Parnell wrote:
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard? 
 
 For arrays we have the 'dup' property but for objects there is nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.
 
 Example:
 
   class Foo
   {
       int x;
       Bar b;
 
       this(int y) 
       {
            x = y;
            b = new Bar(y);
       }
 
       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }
 
    . . . 
 
    auto backup = q.onCopy();
 
 And maybe one day (hoping against precedent) that Walter will actually see
 that an operator for copying stuff is not such a stupid idea.
 
    auto backup := q; // invokes q.onCopy() if it exists.
 

a compiler generated .dup method would be nice.
Aug 03 2006
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Hasan Aljudy wrote:
 
 a compiler generated .dup method would be nice.

Reflection and the ability to generate your own would be even better.
Aug 03 2006
parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Tom S wrote:
 Hasan Aljudy wrote:
 
 a compiler generated .dup method would be nice.

Reflection and the ability to generate your own would be even better.

well you already can create your own .dup I mean it's just a method that returns typeof(this)
Aug 03 2006
parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Hasan Aljudy wrote:
 
 
 Tom S wrote:
 Hasan Aljudy wrote:

 a compiler generated .dup method would be nice.

Reflection and the ability to generate your own would be even better.

well you already can create your own .dup I mean it's just a method that returns typeof(this)

There was a subtle difference in what I wrote :) 'generate' vs 'create' - that is. Generating own .dup and/or serialization functions based on meta data is different than writing/creating your own routines to handle that by hand. -- Tomasz Stachowiak
Aug 03 2006
parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Tom S wrote:
 Hasan Aljudy wrote:
 
 Tom S wrote:

 Hasan Aljudy wrote:

 a compiler generated .dup method would be nice.

Reflection and the ability to generate your own would be even better.

well you already can create your own .dup I mean it's just a method that returns typeof(this)

There was a subtle difference in what I wrote :) 'generate' vs 'create' - that is. Generating own .dup and/or serialization functions based on meta data is different than writing/creating your own routines to handle that by hand. -- Tomasz Stachowiak

Sorry, what's the difference of writing code and "generating code by yourself"?
Aug 03 2006
parent Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Hasan Aljudy wrote:
 
 
 Tom S wrote:
 Hasan Aljudy wrote:

 Tom S wrote:

 Hasan Aljudy wrote:

 a compiler generated .dup method would be nice.

Reflection and the ability to generate your own would be even better.

well you already can create your own .dup I mean it's just a method that returns typeof(this)

There was a subtle difference in what I wrote :) 'generate' vs 'create' - that is. Generating own .dup and/or serialization functions based on meta data is different than writing/creating your own routines to handle that by hand. -- Tomasz Stachowiak

Sorry, what's the difference of writing code and "generating code by yourself"?

I didn't write 'generating code by yourself'. Anyway, in this context: If you wanted the .dup to behave in such a way that e.g. it would do a binary copy of all structs and built-in types, and recursively call .dup on all object members of a given class that support the .dup method then... you'd have to write it by hand for each class. Also, you'd have to update the .dup method upon each modification of the class' members. On the other hand, if D had good reflection support, it would be possible to e.g. define a mixin that detects what fields a given class contains and generates your custom-tailored .dup method. -- Tomasz Stachowiak
Aug 03 2006
prev sibling next sibling parent "Lionello Lunesu" <lio lunesu.remove.com> writes:
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:4war8mij9m44$.1xwxnpe32ro4e$.dlg 40tude.net...
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard?

 For arrays we have the 'dup' property but for objects there is nothing 
 that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.

What's stopping you from using "dup" as the name? #class Test { # Test dup() { # return new Test; # } #} #void main() { # Test t = new Test; # Test a = t.dup; #} L.
Aug 03 2006
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek Parnell wrote:
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard? 
 
 For arrays we have the 'dup' property but for objects there is nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.
 
 Example:
 
   class Foo
   {
       int x;
       Bar b;
 
       this(int y) 
       {
            x = y;
            b = new Bar(y);
       }
 
       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }
 
    . . . 
 
    auto backup = q.onCopy();
 

What's the "on" prefix for? I think the name should be something like: dup() Clone() Copy() and it should exist by default in the Object class, with a default implementation that does a shallow copy. Also, it is redundant to specify a shallow copy function for each class: the code is the same for any class. It is something like: Object ShallowCopy(Object obj) { int len = obj.classinfo.init.length; auto data = (cast(ubyte*) obj)[0..len]; return cast(Object) data.dup.ptr; } So there should not be two different functions for each kind of copy, there should be only one, which conceptually is defined to do a deep copy.
 And maybe one day (hoping against precedent) that Walter will actually see
 that an operator for copying stuff is not such a stupid idea.
 
    auto backup := q; // invokes q.onCopy() if it exists.
 

Yes, I think that would be quite useful. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 03 2006
next sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Bruno Medeiros wrote:
 Derek Parnell wrote:
 

 And maybe one day (hoping against precedent) that Walter will actually 
 see
 that an operator for copying stuff is not such a stupid idea.

    auto backup := q; // invokes q.onCopy() if it exists.

Yes, I think that would be quite useful.

Oh please, I hate the := operator, it's too ugly.
Aug 03 2006
parent reply Derek <derek psyc.ward> writes:
On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:

 Bruno Medeiros wrote:
 Derek Parnell wrote:
 

 And maybe one day (hoping against precedent) that Walter will actually 
 see
 that an operator for copying stuff is not such a stupid idea.

    auto backup := q; // invokes q.onCopy() if it exists.

Yes, I think that would be quite useful.

Oh please, I hate the := operator, it's too ugly.

I don't give a damn what operator is used, this was *JUST AN EXAMPLE*. Please, feel free to suggest other things that might be suitable for a deep-copy operator. One that would be usable on all data types and meants that the information in the left-hand-side thingy would be copied and the right-hand thingy would 'hold' that copy. For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever (the name doesn't matter) if it existed, otherwise its a compile time error. The function would return the same datatype as the object that owns the function, meaning that Foo.onDup can't return a Bar or its parent type or an interface - it must return a Foo object instance. For arrays it is identical to the .dup property. For basic datatypes it is identical to moving the bit value from one to another variable (no conversion or transformations allowed). Therefore the lefthand side and righthand side thingy must be the same datatype. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 03 2006
next sibling parent reply Hasan Aljudy <hasan.aljudy gmail.com> writes:
Derek wrote:
 On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:
 
 
Bruno Medeiros wrote:

Derek Parnell wrote:

<Snip>
And maybe one day (hoping against precedent) that Walter will actually 
see
that an operator for copying stuff is not such a stupid idea.

   auto backup := q; // invokes q.onCopy() if it exists.

Yes, I think that would be quite useful.

Oh please, I hate the := operator, it's too ugly.

I don't give a damn what operator is used, this was *JUST AN EXAMPLE*. Please, feel free to suggest other things that might be suitable for a deep-copy operator. One that would be usable on all data types and meants that the information in the left-hand-side thingy would be copied and the right-hand thingy would 'hold' that copy. For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever (the name doesn't matter) if it existed, otherwise its a compile time error. The function would return the same datatype as the object that owns the function, meaning that Foo.onDup can't return a Bar or its parent type or an interface - it must return a Foo object instance. For arrays it is identical to the .dup property. For basic datatypes it is identical to moving the bit value from one to another variable (no conversion or transformations allowed). Therefore the lefthand side and righthand side thingy must be the same datatype.

why an operator? a method/property is more suitable, I think.
Aug 03 2006
next sibling parent Derek <derek psyc.ward> writes:
On Thu, 03 Aug 2006 17:12:39 -0600, Hasan Aljudy wrote:

 why an operator?
 a method/property is more suitable, I think.

Where does this train of thought stop? Why an operator for anything? Do we need '=' '>=' '+=' etc... when we have all those useful opXXX functions handy? Of course we do, because it makes coding easier to read and write. The action of cloning an item is quite a common action and having to use a method name is not as convenient as an operator. Also, an operator can act with objects, structs, arrays, and basic-types where as method names don't work so well with all types. This simplifies template construction. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 03 2006
prev sibling parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Hasan Aljudy wrote:
 
 
 Derek wrote:
 
 On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:


 Bruno Medeiros wrote:

 Derek Parnell wrote:

<Snip>
 And maybe one day (hoping against precedent) that Walter will 
 actually see
 that an operator for copying stuff is not such a stupid idea.

   auto backup := q; // invokes q.onCopy() if it exists.

Yes, I think that would be quite useful.

Oh please, I hate the := operator, it's too ugly.

I don't give a damn what operator is used, this was *JUST AN EXAMPLE*. Please, feel free to suggest other things that might be suitable for a deep-copy operator. One that would be usable on all data types and meants that the information in the left-hand-side thingy would be copied and the right-hand thingy would 'hold' that copy. For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever (the name doesn't matter) if it existed, otherwise its a compile time error. The function would return the same datatype as the object that owns the function, meaning that Foo.onDup can't return a Bar or its parent type or an interface - it must return a Foo object instance. For arrays it is identical to the .dup property. For basic datatypes it is identical to moving the bit value from one to another variable (no conversion or transformations allowed). Therefore the lefthand side and righthand side thingy must be the same datatype.

why an operator? a method/property is more suitable, I think.

People used to C++ are used to doing this with an operator overload. People used to some other languages (e.g. Python) will be more used to using a method (or even a library function, in the case of Python). I honestly don't think it matters. One could also argue for the use of copy constructors, of course. This may be getting too close to C++ for some people's tastes, though. (The syntax is also more verbose than a simple .dup property.) class Foo { int m_i; this(int i) { m_i = i; } this(Foo f) { m_i = f.m_i; } } Foo a, b; a = new Foo(20); b = new Foo(a); This does have the advantage of using "new" to make it clear that we are allocating a new object (though I don't think this is really a problem with just using .dup). With reflection support, we could even give Object a useful default copy constructor, as Tom S pointed out. -- Kirk McDonald Pyd: Wrapping Python with D http://dsource.org/projects/pyd/wiki
Aug 03 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 03 Aug 2006 16:28:25 -0700, Kirk McDonald wrote:

 People used to C++ are used to doing this with an operator overload. 
 People used to some other languages (e.g. Python) will be more used to 
 using a method (or even a library function, in the case of Python). I 
 honestly don't think it matters.
 
 One could also argue for the use of copy constructors, of course. This 
 may be getting too close to C++ for some people's tastes, though. (The 
 syntax is also more verbose than a simple .dup property.)

Copy constructors and 'standard' functions would have to work with basic types, structs and arrays too for it to be really useful.
 class Foo {
      int m_i;
      this(int i) { m_i = i; }
      this(Foo f) { m_i = f.m_i; }
 }
 
 Foo a, b;
 a = new Foo(20);
 b = new Foo(a);
 
 This does have the advantage of using "new" to make it clear that we are 
 allocating a new object (though I don't think this is really a problem 
 with just using .dup).
 
 With reflection support, we could even give Object a useful default copy 
 constructor, as Tom S pointed out.

Not everything is an object. <g> template backup(T) { void backup(inout T[] st, T dt) { st.length = st.length + 1; st[$-1] := dt; // Invokes opDup for classes and structs, // .dup for arrays, // binary copy for everything else } } int[] istore; backup( istore, anInt); Foo[] foostore; backup( foostore, aFoo); -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 4/08/2006 10:40:00 AM
Aug 03 2006
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Derek Parnell wrote:
 On Thu, 03 Aug 2006 16:28:25 -0700, Kirk McDonald wrote:
 
 
People used to C++ are used to doing this with an operator overload. 
People used to some other languages (e.g. Python) will be more used to 
using a method (or even a library function, in the case of Python). I 
honestly don't think it matters.

One could also argue for the use of copy constructors, of course. This 
may be getting too close to C++ for some people's tastes, though. (The 
syntax is also more verbose than a simple .dup property.)

Copy constructors and 'standard' functions would have to work with basic types, structs and arrays too for it to be really useful.

Of course. :-)
  
 
class Foo {
     int m_i;
     this(int i) { m_i = i; }
     this(Foo f) { m_i = f.m_i; }
}

Foo a, b;
a = new Foo(20);
b = new Foo(a);

This does have the advantage of using "new" to make it clear that we are 
allocating a new object (though I don't think this is really a problem 
with just using .dup).

With reflection support, we could even give Object a useful default copy 
constructor, as Tom S pointed out.

Not everything is an object. <g> template backup(T) { void backup(inout T[] st, T dt) { st.length = st.length + 1; st[$-1] := dt; // Invokes opDup for classes and structs, // .dup for arrays, // binary copy for everything else } } int[] istore; backup( istore, anInt); Foo[] foostore; backup( foostore, aFoo);

opDup appeals to me, but more consistent would probably be a standard .dup property. Despite what others have said, := is not a terrible operator. However, having := be overloaded with a "dup" function instead of an "opDup" function is inconsistent with the other operator overloads. So let's get the problem clear before we go proposing solutions: We want a standard way of getting a copy of an object. We can either use an operator for this purpose (such as :=), or a standard method (such as .dup, as arrays currently use for the same purpose). The := operator should work for classes, structs, arrays, and other primitive types. Arrays already have the .dup property, so := can use that. Remember that structs use value semantics. Assigning a struct the normal way copies its members. So, for structs and the various primitive types (that is to say, all of the types that use value semantics), := will be identical to a regular assignment. I suggest a copy constructor as a way of overloading := for class objects. This is a C++ thing, but it is actually a fairly elegant solution, I think. The complication, now, is getting a constant way of getting a copy of some object or value when we don't actually want to assign it to anything (say, in a function call). My initial thought is to use unary : to mean "copy-of" (this is consistent with the := operator), but (not knowing much about how the parser works), I can't help but think that this might interfere with labels or the trinary ?: operator or something. Someone care to comment on that? The syntax looks fine: fn( i, j, :obj); // send a copy of obj to the function So, for both the proposed := copy-assignment operator and unary : copy operator, the various copying mechanisms would be: class instances: copy constructor arrays/AAs: dup property structs, primitive types, etc: by-value copy We wouldn't even have to provide a copy constructor in Object, you know. Trying to use these operators on an instance of a class that doesn't define a copy constructor would just be a compiler error, like any other undefined operator overload or method you try to use. Thoughts? -- Kirk McDonald Pyd: Wrapping Python with D http://dsource.org/projects/pyd/wiki
Aug 03 2006
next sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 03 Aug 2006 23:19:23 -0700, Kirk McDonald wrote:

 opDup appeals to me

Me too <g>
 , but more consistent would probably be a standard 
 .dup property. Despite what others have said, := is not a terrible 
 operator. 

Agreed, but I'm not really fussed.
 However, having := be overloaded with a "dup" function instead 
 of an "opDup" function is inconsistent with the other operator overloads.

Yes. Let's stick with consistency.
 So let's get the problem clear before we go proposing solutions: We want 
 a standard way of getting a copy of an object. 

Rather than using the term 'object' here, let's use the term 'item' because it is not so ambiguous. In this way, 'item' can mean every data type supported by D.
 We can either use an 
 operator for this purpose (such as :=), or a standard method (such as 
 .dup, as arrays currently use for the same purpose).
 
 The := operator should work for classes, structs, arrays, and other 
 primitive types. Arrays already have the .dup property, so := can use 
 that. Remember that structs use value semantics. Assigning a struct the 
 normal way copies its members. So, for structs and the various primitive 
 types (that is to say, all of the types that use value semantics), := 
 will be identical to a regular assignment.

Hmmm... not so certain about that. A shallow copy (bit-by-bit) is already performed by .dup and struct assignment, but we need a neat way to express that we want a deep copy done. That is, we want the information copied and not just the bits in the source item. Such that if an item contains references (dynamic arrays, objects, and other pointers) it might want to take copies of all their contents too. char[][] theFile; char[][] backup; . . . backup := theFile; // Make a copy of all the strings, not just // the references to the strings. class Foo { Bar b; } Foo a := aFoo; // Takes a copy of the Foo object *and* the // contained Bar object, not just a copy of // the reference to the Bar object.
 I suggest a copy constructor as a way of overloading := for class 
 objects. This is a C++ thing, but it is actually a fairly elegant 
 solution, I think.

Whatever. I'm not fussed how its done so long as it makes writing and reading code easier to do.
 The complication, now, is getting a constant way of getting a copy of 
 some object or value when we don't actually want to assign it to 
 anything (say, in a function call). My initial thought is to use unary : 
 to mean "copy-of" (this is consistent with the := operator), but (not 
 knowing much about how the parser works), I can't help but think that 
 this might interfere with labels or the trinary ?: operator or 
 something. Someone care to comment on that? The syntax looks fine:
 
 fn( i, j, :obj); // send a copy of obj to the function

How about ... fn(i, j, auto := obj); //??? as the keyword 'auto' already implies a temporary object that is automatically destroyed when end of scope is reached.
 So, for both the proposed := copy-assignment operator and unary : copy 
 operator, the various copying mechanisms would be:
 
 class instances:                copy constructor

Ok, whatever.
 arrays/AAs:                     dup property

Nah ... needs a 'copy constructor' too, I think.
 structs, 

 primitive types, etc:  by-value copy

Ok.
 We wouldn't even have to provide a copy constructor in Object, you know. 
 Trying to use these operators on an instance of a class that doesn't 
 define a copy constructor would just be a compiler error, like any other 
 undefined operator overload or method you try to use.

Yeah, doesn't matter that much to me either way.
 Thoughts?

hmmm...chocolate-iced donut and hot coffee, but that's not relevant I guess. <g> -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 4/08/2006 4:29:20 PM
Aug 03 2006
parent Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Derek Parnell wrote:
 On Thu, 03 Aug 2006 23:19:23 -0700, Kirk McDonald wrote:
So let's get the problem clear before we go proposing solutions: We want 
a standard way of getting a copy of an object. 

Rather than using the term 'object' here, let's use the term 'item' because it is not so ambiguous. In this way, 'item' can mean every data type supported by D.

"Item" it is!
We can either use an 
operator for this purpose (such as :=), or a standard method (such as 
.dup, as arrays currently use for the same purpose).

The := operator should work for classes, structs, arrays, and other 
primitive types. Arrays already have the .dup property, so := can use 
that. Remember that structs use value semantics. Assigning a struct the 
normal way copies its members. So, for structs and the various primitive 
types (that is to say, all of the types that use value semantics), := 
will be identical to a regular assignment.

Hmmm... not so certain about that. A shallow copy (bit-by-bit) is already performed by .dup and struct assignment, but we need a neat way to express that we want a deep copy done. That is, we want the information copied and not just the bits in the source item. Such that if an item contains references (dynamic arrays, objects, and other pointers) it might want to take copies of all their contents too. char[][] theFile; char[][] backup; . . . backup := theFile; // Make a copy of all the strings, not just // the references to the strings. class Foo { Bar b; } Foo a := aFoo; // Takes a copy of the Foo object *and* the // contained Bar object, not just a copy of // the reference to the Bar object.

Do we want this to mean a deep copy? The only distinction we (I?) have been talking in terms of is the simple case, so I guess it hasn't been addressed, yet. Python, for the record, allows classes to define both a __copy__ and a __deepcopy__ method (the double-underscores are Python's standard notation for operator overloading), and provides both a copy() and a deepcopy() library function. If a class doesn't provide a __copy__ or __deepcopy__ method, the library functions will use Python's introspective capabilities and do a naive copy or deep copy. (This is usually adequate.) I am rapidly thinking that an operator is a bad idea. Please disregard my earlier musings on the idea. :-) So! Define .dup to mean a shallow copy for classes. Object should not provide it. Classes that want to provide it, can. (This happily requires zero changes to the language! Hooray!) For consistency's sake, dup should be provided for primitive types. (This may simplify template code.) Structs should provide it as a bit-by-bit copy, just like regular assignment does now. I am split on whether users should be able to overload it for structs. I can't think of a good reason why one /would/ overload it, but then I can't think of a good, specific reason to disallow it, either. A second standard property should be provided for deep copying. I suggest "deepcopy". As with 'dup', classes can provide this or not. Attempting to deepcopy an array of a class that doesn't provide a deepcopy property, or a struct containing such a class, should be a compile error. As with .dup, it should be provided for primitive types as an aid for template code. If it is really wanted, := can be provided as a shortcut for assigning to a deepcopy. However (as I pointed out earlier) this would be inconsistent with the other operator overload names, and so I don't think it's really a good idea. Using a copy constructor for either of these is probably not a good idea, as it doesn't imply anything about whether the copy is shallow or deep. (Naturally, classes can still provide one for their own nefarious purposes.) -- Kirk McDonald Pyd: Wrapping Python with D http://dsource.org/projects/pyd/wiki
Aug 04 2006
prev sibling parent reply kris <foo bar.com> writes:
Kirk McDonald wrote:

[snip]

 fn( i, j, :obj); // send a copy of obj to the function
 
 So, for both the proposed := copy-assignment operator and unary : copy 
 operator, the various copying mechanisms would be:
 
 class instances:                copy constructor
 arrays/AAs:                     dup property
 structs, primitive types, etc:  by-value copy
 
 We wouldn't even have to provide a copy constructor in Object, you know. 
 Trying to use these operators on an instance of a class that doesn't 
 define a copy constructor would just be a compiler error, like any other 
 undefined operator overload or method you try to use.
 
 Thoughts?
 

yeah :) Sorry, Kirk, but this kinda stinks: # fn( i, j, :obj); I don't see any point of introducing obtuse operators when consistency would dictate something like this: # fn( i, j, obj.dup); The compiler can just as easily support a generic (shallow) .dup for classes as it can for other types. Alternatively, simply add a final dup() method to the root Object? Does deep-copy really need an operator? I have to wonder whether a simple naming-convention would do the trick instead ... that way, you'd never have a /default/ deep-copy, and usage mistakes would produce a most welcome compile-time error.
Aug 03 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:

 Does deep-copy really need an operator? I have to wonder whether a 
 simple naming-convention would do the trick instead  ... that way, you'd 
 never have a /default/ deep-copy, and usage mistakes would produce a 
 most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly. This could never work 100% with a "naming-convention" as it is no compiler enforced. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 4/08/2006 4:57:48 PM
Aug 04 2006
parent reply kris <foo bar.com> writes:
Derek Parnell wrote:
 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:
 
 
Does deep-copy really need an operator? I have to wonder whether a 
simple naming-convention would do the trick instead  ... that way, you'd 
never have a /default/ deep-copy, and usage mistakes would produce a 
most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)
Aug 04 2006
parent reply Dave <Dave_member pathlink.com> writes:
kris wrote:
 Derek Parnell wrote:
 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:


 Does deep-copy really need an operator? I have to wonder whether a 
 simple naming-convention would do the trick instead  ... that way, 
 you'd never have a /default/ deep-copy, and usage mistakes would 
 produce a most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)

With all that in mind - if .dup was given an op overload for classes and structs, couldn't that then be used to do the deep copy when it was imperative? For example: class C // built-in .dup copies i and the reference to str { int i; char[] str; } class D // .dup is overloaded to do a default shallow and optional deep copy { int i; char[] str; C opDup(bool deep = false) { C c = new C; c.i = this.i; if(deep) c.str = this.str.dup; else c.str = this.str; return c; } } - Dave
Aug 04 2006
parent reply kris <foo bar.com> writes:
Dave wrote:
 kris wrote:
 
 Derek Parnell wrote:

 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:


 Does deep-copy really need an operator? I have to wonder whether a 
 simple naming-convention would do the trick instead  ... that way, 
 you'd never have a /default/ deep-copy, and usage mistakes would 
 produce a most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)

With all that in mind - if .dup was given an op overload for classes and structs, couldn't that then be used to do the deep copy when it was imperative? For example: class C // built-in .dup copies i and the reference to str { int i; char[] str; } class D // .dup is overloaded to do a default shallow and optional deep copy { int i; char[] str; C opDup(bool deep = false) { C c = new C; c.i = this.i; if(deep) c.str = this.str.dup; else c.str = this.str; return c; } } - Dave

The issue I see, mixing deep & shallow copy like this, is that misuse would have to be noted at runtime rather than at compile-time?
Aug 04 2006
parent reply Dave <Dave_member pathlink.com> writes:
kris wrote:
 Dave wrote:
 kris wrote:

 Derek Parnell wrote:

 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:


 Does deep-copy really need an operator? I have to wonder whether a 
 simple naming-convention would do the trick instead  ... that way, 
 you'd never have a /default/ deep-copy, and usage mistakes would 
 produce a most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)

With all that in mind - if .dup was given an op overload for classes and structs, couldn't that then be used to do the deep copy when it was imperative? For example: class C // built-in .dup copies i and the reference to str { int i; char[] str; } class D // .dup is overloaded to do a default shallow and optional deep copy { int i; char[] str; C opDup(bool deep = false) { C c = new C; c.i = this.i; if(deep) c.str = this.str.dup; else c.str = this.str; return c; } } - Dave

The issue I see, mixing deep & shallow copy like this, is that misuse would have to be noted at runtime rather than at compile-time?

Yea that's a drawback. Just trying to figure out how things could be done with '.dup' and I was thinking along the lines of deep copy not being used all that often (so it could just be built into an opDup overload and always made intentional). Or if the class developer always intended a deep copy for some reason then they could just code that as well.
Aug 04 2006
parent reply kris <foo bar.com> writes:
Dave wrote:
 kris wrote:
 
 Dave wrote:

 kris wrote:

 Derek Parnell wrote:

 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:


 Does deep-copy really need an operator? I have to wonder whether a 
 simple naming-convention would do the trick instead  ... that way, 
 you'd never have a /default/ deep-copy, and usage mistakes would 
 produce a most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)

With all that in mind - if .dup was given an op overload for classes and structs, couldn't that then be used to do the deep copy when it was imperative? For example: class C // built-in .dup copies i and the reference to str { int i; char[] str; } class D // .dup is overloaded to do a default shallow and optional deep copy { int i; char[] str; C opDup(bool deep = false) { C c = new C; c.i = this.i; if(deep) c.str = this.str.dup; else c.str = this.str; return c; } } - Dave

The issue I see, mixing deep & shallow copy like this, is that misuse would have to be noted at runtime rather than at compile-time?

Yea that's a drawback. Just trying to figure out how things could be done with '.dup' and I was thinking along the lines of deep copy not being used all that often (so it could just be built into an opDup overload and always made intentional). Or if the class developer always intended a deep copy for some reason then they could just code that as well.

Aye. But does it cover Derek's concern of deep-copy for arrays and so on? I suppose one argument could be that since deep-copy seems to be fairly rare, it's perhaps not really an issue to wrap the entity in an aggregate ;) Seems like the two are sufficiently different in terms of both meaning and usage patterns; perhaps they should be isolated? BTW: one concern I'd have with a root-Object dup() method is the need to cast the returned instance. Presumeably a more specific compiler implementation (of object.dup) would sidestep that need for casting?
Aug 04 2006
next sibling parent Dave <Dave_member pathlink.com> writes:
kris wrote:
 Dave wrote:
 kris wrote:

 Dave wrote:

 kris wrote:

 Derek Parnell wrote:

 On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote:


 Does deep-copy really need an operator? I have to wonder whether 
 a simple naming-convention would do the trick instead  ... that 
 way, you'd never have a /default/ deep-copy, and usage mistakes 
 would produce a most welcome compile-time error.

I'm not asking for a default deep copy. If you haven't defined one then its a compile time error. How would a function/method work with arrays as .dup only does a shallow copy. And how would it work in templates that use basic types? An operator overcomes these issues by letting the compiler know what the coder's intentions are and generate code accordingly.

True. If I have an array of char*, an array of class refs, or something similar, and want a deep copy, then an operator might be a fair option. But so would the ability to add methods to arrays (for example), which would be far more powerful (and competitive with C#) than one specific deep-copy facility. On the other hand, one has to wonder how often deep copy is actually used? In 22 years of paid R&D (pretty much across the spectrum too) I can recall using deep-copy perhaps less than half a dozen times? As operations go, it's typically a rather expensive one. Most folk seem to try and find a way around that instead? Certainly it might be nice to have, but is it really more important than, say, fixing static-arrays? You didn't say that, or rank deep-copy in any way, but one has to wonder? All that aside, .dup() is still a better approach for shallow copy :)

With all that in mind - if .dup was given an op overload for classes and structs, couldn't that then be used to do the deep copy when it was imperative? For example: class C // built-in .dup copies i and the reference to str { int i; char[] str; } class D // .dup is overloaded to do a default shallow and optional deep copy { int i; char[] str; C opDup(bool deep = false) { C c = new C; c.i = this.i; if(deep) c.str = this.str.dup; else c.str = this.str; return c; } } - Dave

The issue I see, mixing deep & shallow copy like this, is that misuse would have to be noted at runtime rather than at compile-time?

Yea that's a drawback. Just trying to figure out how things could be done with '.dup' and I was thinking along the lines of deep copy not being used all that often (so it could just be built into an opDup overload and always made intentional). Or if the class developer always intended a deep copy for some reason then they could just code that as well.

Aye. But does it cover Derek's concern of deep-copy for arrays and so

Nope <g>
 on? I suppose one argument could be that since deep-copy seems to be 
 fairly rare, it's perhaps not really an issue to wrap the entity in an 
 aggregate ;)
 

I would say - everytime I've seen 'deep' copies done on the elements of an array of objects there's some sort of iterator and loop involved. But of course that's with C++ that doesn't have any notion of .dup built in.
 Seems like the two are sufficiently different in terms of both meaning 
 and usage patterns; perhaps they should be isolated?
 

I guess so, especially if you wanted to build something that would recurse through elements, like: MyObject[] array; ... array.dup; // would .dup the array and call .dup on each element. Hmmm, how to copy just the array? array.deep; // would .dup the array and call .deep on each element. Something like that? (Of course for arrays of value types the compiler would have to figure out that .dup and .deep do the same thing and don't recurse).
 BTW: one concern I'd have with a root-Object dup() method is the need to 
 cast the returned instance. Presumeably a more specific compiler 
 implementation (of object.dup) would sidestep that need for casting?

I agree.
Aug 04 2006
prev sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
kris wrote:
 
 BTW: one concern I'd have with a root-Object dup() method is the need to 
 cast the returned instance. Presumeably a more specific compiler 
 implementation (of object.dup) would sidestep that need for casting?

There is no need for casting. Since D supports covariant return types, the overriding methods can return their specific types: class Foo { Foo Clone() { return new Foo(); } } class FooBar : Foo { override FooBar Clone() { return new FooBar(); } } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2006
parent reply kris <foo bar.com> writes:
Bruno Medeiros wrote:
 kris wrote:
 
 BTW: one concern I'd have with a root-Object dup() method is the need 
 to cast the returned instance. Presumeably a more specific compiler 
 implementation (of object.dup) would sidestep that need for casting?

There is no need for casting. Since D supports covariant return types, the overriding methods can return their specific types: class Foo { Foo Clone() { return new Foo(); } } class FooBar : Foo { override FooBar Clone() { return new FooBar(); } }

Yes, we're well aware of the covariance aspect. However, we'd been talking about /one/ method to handle all shallow class copy (perhaps in the root Object, as was noted). Why one method? So (a) you don't have to add the above to each and every class that might possibly be copied at some point in the future, and (b) you don't end up being confused when you dup a class and wind-up with a partial copy (and a cast requirement) when a superclass method is invoked instead. Covariance is all well and good, but we stepped beyond that point early on. Perhaps you'll re-read the first paragraph again and understand it better?
Aug 08 2006
parent Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
kris wrote:
 Bruno Medeiros wrote:
 kris wrote:

 BTW: one concern I'd have with a root-Object dup() method is the need 
 to cast the returned instance. Presumeably a more specific compiler 
 implementation (of object.dup) would sidestep that need for casting?

There is no need for casting. Since D supports covariant return types, the overriding methods can return their specific types: class Foo { Foo Clone() { return new Foo(); } } class FooBar : Foo { override FooBar Clone() { return new FooBar(); } }

Yes, we're well aware of the covariance aspect. However, we'd been talking about /one/ method to handle all shallow class copy (perhaps in the root Object, as was noted). Why one method? So (a) you don't have to add the above to each and every class that might possibly be copied at some point in the future, and (b) you don't end up being confused when you dup a class and wind-up with a partial copy (and a cast requirement) when a superclass method is invoked instead. Covariance is all well and good, but we stepped beyond that point early on. Perhaps you'll re-read the first paragraph again and understand it better?

Hum, you're right, I thought you were talking about deep copy. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2006
prev sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek wrote:
 On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:
 
 
 Please, feel free to suggest other things that might be suitable for a
 deep-copy operator. One that would be usable on all data types and meants
 that the information in the left-hand-side thingy would be copied and the
 right-hand thingy would 'hold' that copy.
 
 For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever
 (the name doesn't matter) if it existed, otherwise its a compile time
 error. The function would return the same datatype as the object that owns
 the function, meaning that Foo.onDup can't return a Bar or its parent type
 or an interface - it must return a Foo object instance.
 
 For arrays it is identical to the .dup property.
 
 For basic datatypes it is identical to moving the bit value from one to
 another variable (no conversion or transformations allowed).
 
 Therefore the lefthand side and righthand side thingy must be the same
 datatype.
 

I've just realized a little nuance that both I and the rest of us are tripping on: There are two similar but distinct notions of a copy operation, not just one. The first one, usually called duping or cloning, is creating a new instance which is a copy of an existing item/data-instance (a one operand operation). The second one, is copying one item to another existing one (a two operand operation), which is more general than the former. Note the difference between the terms "create a copy" and simply "copy". We've been mixing these two concepts a bit, but they should be clearly separate. It won't work well to try to have one do the job of the other, rather we can have both in the language: foo.opCopy(bar) // copies bar into foo; foo := bar // same as above foo.Clone() // creates a (deep) copy of foo note that Clone is the same (conceptually at least) as: (new typeof(foo)).opCopy(foo); or even: foo.dup.opCopy(foo); if .dup does a shallow copy. One could also think of a two-operand shallow-copy operation, but that seems like going too far, I don't believe that would be useful. In fact, I'm also not that sure if it is much useful for a datatype that already has a deep self-copy function to have shallow self-copy too. Derek mention the example of arrays, but even so... Clone should be a virtual method in the Object hierarchy. As for opCopy, I'm not sure. If it is a final method, you're limited in what you can do with polymorphism. If it is virtual method, then the method has to have a parameter of type Object, and so one has to write some dynamic dispatch code in the method to handle the proper runtime types. The names could be other of course, but my suggestion is as per the examples above: self-copy is called "Clone" or "dup", and two-operand copy is "Copy" or "opCopy". The names "dup" and "Clone" are likely inappropriate for a Copy operation. Additionally, we could maybe also call "Clone" to the *deep* copying, and "dup" to *shallow* copying, if there is a need to have both. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2006
parent reply kris <foo bar.com> writes:
Bruno Medeiros wrote:
 Derek wrote:
 
 On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:


 Please, feel free to suggest other things that might be suitable for a
 deep-copy operator. One that would be usable on all data types and meants
 that the information in the left-hand-side thingy would be copied and the
 right-hand thingy would 'hold' that copy.

 For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever
 (the name doesn't matter) if it existed, otherwise its a compile time
 error. The function would return the same datatype as the object that 
 owns
 the function, meaning that Foo.onDup can't return a Bar or its parent 
 type
 or an interface - it must return a Foo object instance.

 For arrays it is identical to the .dup property.

 For basic datatypes it is identical to moving the bit value from one to
 another variable (no conversion or transformations allowed).

 Therefore the lefthand side and righthand side thingy must be the same
 datatype.

I've just realized a little nuance that both I and the rest of us are tripping on: There are two similar but distinct notions of a copy operation, not just one.

Speak for yourself, Bruno: all of this is simply taken for granted in some of the other posts.
 The first one, usually called duping or cloning, is creating a new 
 instance which is a copy of an existing item/data-instance (a one 
 operand operation).
 The second one, is copying one item to another existing one (a two 
 operand operation), which is more general than the former.
 Note the difference between the terms "create a copy" and simply "copy".
 
 We've been mixing these two concepts a bit, but they should be clearly 
 separate. It won't work well to try to have one do the job of the other, 
 rather we can have both in the language:
 
   foo.opCopy(bar)  // copies bar into foo;
   foo := bar       // same as above
   foo.Clone()      // creates a (deep) copy of foo
 
 note that Clone is the same (conceptually at least) as:
   (new typeof(foo)).opCopy(foo);
 or even:
   foo.dup.opCopy(foo);
 if .dup does a shallow copy.
 
 One could also think of a two-operand shallow-copy operation, but that 
 seems like going too far, I don't believe that would be useful.
 
 In fact, I'm also not that sure if it is much useful for a datatype that 
 already has a deep self-copy function to have shallow self-copy too. 
 Derek mention the example of arrays, but even so...
 
 Clone should be a virtual method in the Object hierarchy. As for opCopy, 
 I'm not sure. If it is a final method, you're limited in what you can do 
 with polymorphism. If it is virtual method, then the method has to have 
 a parameter of type Object, and so one has to write some dynamic 
 dispatch code in the method to handle the proper runtime types.
 
 The names could be other of course, but my suggestion is as per the 
 examples above: self-copy is called "Clone" or "dup", and two-operand 
 copy is "Copy" or "opCopy". The names "dup" and "Clone" are likely 
 inappropriate for a Copy operation.
 Additionally, we could maybe also call "Clone" to the *deep* copying, 
 and "dup" to *shallow* copying, if there is a need to have both.
 

Aug 08 2006
parent Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
kris wrote:
 Bruno Medeiros wrote:
 Derek wrote:

 On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:


 Please, feel free to suggest other things that might be suitable for a
 deep-copy operator. One that would be usable on all data types and 
 meants
 that the information in the left-hand-side thingy would be copied and 
 the
 right-hand thingy would 'hold' that copy.

 For objects, it would invoke onDup/onCopy/onClone/onDeepCopy/onWhatever
 (the name doesn't matter) if it existed, otherwise its a compile time
 error. The function would return the same datatype as the object that 
 owns
 the function, meaning that Foo.onDup can't return a Bar or its parent 
 type
 or an interface - it must return a Foo object instance.

 For arrays it is identical to the .dup property.

 For basic datatypes it is identical to moving the bit value from one to
 another variable (no conversion or transformations allowed).

 Therefore the lefthand side and righthand side thingy must be the same
 datatype.

I've just realized a little nuance that both I and the rest of us are tripping on: There are two similar but distinct notions of a copy operation, not just one.

Speak for yourself, Bruno: all of this is simply taken for granted in some of the other posts.

I was writing a reply in how that was not so, and people where blending the two things, but... Whoa! I just realized you are right, I was way off-course and I've been misunderstanding this thread since the beginning. To make sure, going back: Derek Wrote: [...]
 
 And maybe one day (hoping against precedent) that Walter will actually see
 that an operator for copying stuff is not such a stupid idea.
 
    auto backup := q; // invokes q.onCopy() if it exists.

Note the last paragraph. What would "auto backup := q;" do? Would it be the same as: auto backup = q.onCopy() right? Then yes, I've seriously misunderstood it, but I think I had some reasons to, I'll comment later. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2006
prev sibling parent reply Derek <derek psyc.ward> writes:
On Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:

 Derek Parnell wrote:
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard? 
 
 For arrays we have the 'dup' property but for objects there is nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.
 
 Example:
 
   class Foo
   {
       int x;
       Bar b;
 
       this(int y) 
       {
            x = y;
            b = new Bar(y);
       }
 
       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }
 
    . . . 
 
    auto backup = q.onCopy();
 

What's the "on" prefix for? I think the name should be something like:

The 'on' prefix is a *hint* to Walter that I'd really like this function to be invoked via a new operator and not necessariliy called directly.
 dup()
 Clone()
 Copy()
 and it should exist by default in the Object class, with a default 
 implementation that does a shallow copy.

Yes, a default shallow copy defined in Object would be a good idea. In that case an operator would not be needed for shallow copying.
 Also, it is redundant to specify a shallow copy function for each class: 
 the code is the same for any class. It is something like:
    Object ShallowCopy(Object obj) {
      int len = obj.classinfo.init.length;
      auto data = (cast(ubyte*) obj)[0..len];
      return cast(Object) data.dup.ptr;
    }
 So there should not be two different functions for each kind of copy, 
 there should be only one, which conceptually is defined to do a deep copy.

Not sure I agree here. The shallow copy coulod be generic as you demonstrated, but a deep copy is very Object-specific and would need to be defined in the class that needed it. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 03 2006
next sibling parent reply Tom S <h3r3tic remove.mat.uni.torun.pl> writes:
Derek wrote:
 On Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:
 
 Derek Parnell wrote:
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard? 

 For arrays we have the 'dup' property but for objects there is nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.

 Example:

   class Foo
   {
       int x;
       Bar b;

       this(int y) 
       {
            x = y;
            b = new Bar(y);
       }

       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }

    . . . 

    auto backup = q.onCopy();


The 'on' prefix is a *hint* to Walter that I'd really like this function to be invoked via a new operator and not necessariliy called directly.

Somehow, 'on' doesn't sound like an operator. On the other hand 'op' does...
Aug 03 2006
next sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
Tom S wrote:
 Derek wrote:
 
 On Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:

 Derek Parnell wrote:

 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions 
 for a
 name that we can all agree on; one that might become an unofficial
 standard?
 For arrays we have the 'dup' property but for objects there is 
 nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe 
 even a
 'onDeepCopy' as an additional function.

 Example:

   class Foo
   {
       int x;
       Bar b;

       this(int y)       {
            x = y;
            b = new Bar(y);
       }

       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }

    . . .
    auto backup = q.onCopy();


The 'on' prefix is a *hint* to Walter that I'd really like this function to be invoked via a new operator and not necessariliy called directly.

Somehow, 'on' doesn't sound like an operator. On the other hand 'op' does...

I think he meant op .. heheh .. when I first read the specs on operator overloading I got confused and, in my mind, I read all the opXxxx functions as onXxxx
Aug 03 2006
prev sibling parent Derek <derek psyc.ward> writes:
On Fri, 04 Aug 2006 00:04:32 +0100, Tom S wrote:


 Somehow, 'on' doesn't sound like an operator. On the other hand 'op' does...

LOL...my mistake. I've been coding too much in another language recently. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 03 2006
prev sibling parent Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek wrote:
 
 Also, it is redundant to specify a shallow copy function for each class: 
 the code is the same for any class. It is something like:
    Object ShallowCopy(Object obj) {
      int len = obj.classinfo.init.length;
      auto data = (cast(ubyte*) obj)[0..len];
      return cast(Object) data.dup.ptr;
    }
 So there should not be two different functions for each kind of copy, 
 there should be only one, which conceptually is defined to do a deep copy.

Not sure I agree here. The shallow copy coulod be generic as you demonstrated, but a deep copy is very Object-specific and would need to be defined in the class that needed it.

I quite agree with what you said, I misstated my comments: when I said "there should not be two different functions", by 'functions' I meant "functions defined by the user". That is, there should not be two different functions defined by the user, as the shallow copy one is redundant, and should exist already. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 08 2006
prev sibling next sibling parent reply Mikola Lysenko <mclysenk mtu.edu> writes:
Adding a virtual deep copy method to Object is a bad idea. Classes such as
sockets or files must never be subjected to such a procedure, since the
result would be unpredictable.

A different solution is to require each type to explicitly state if it 
supports deep-copies at compile time.  This can be done by creating the
convention that all classes which support deep copy define a 'clone'
method.  For the moment, clone needs to be implemented by hand, but given
better introspection it should be possible to create a mixin which
automatically performs this task.

If everyone adheres to this convention, the following templates to allow
anyone to test if a type is clonable at compile time - and easily perform
a clone.  For completeness, there is also a shallow copy or 'dup'
operation using the same technique.

Code:

import std.stdio, std.string;


/**
 * A clone is a deep copy of an object.  It is totally independent
 * of the original object.  Once cloned, the original may be
 * deleted or modified without affecting the copy.
 *
 * All primitives types and structs are clonable by default - except
 * pointers.  Objects are clonable if and only if they define a 
 * clone method.
 *
 * isCloneable tests if a type can be cloned.
 *
 * clone makes a deep copy of the original object.
 */
template isCloneable(T)
{
    static if (is(T A : A[]))
        enum { isCloneable = isCloneable!(A) }
    else static if (is(typeof(&T.clone)))
        enum { isCloneable = true }
    else static if (is(T : Object))
        enum { isCloneable = false }
    else static if (is(T : T *))
        enum { isCloneable = false }
    else
        enum { isCloneable = true }
}


/**
 * Creates a deep copy of the given object.
 *
 * Params:
 *  t = The object we are cloning.
 *
 * Returns:
 *  A deep copy of the original object.
 */
T clone(T)(T obj)
{
    static assert (isCloneable!(T));

    static if(is(T A : A[]))
    {
        A[] res = new A[obj.length];    
        foreach(int i, inout A t; obj)
            res[i] = clone!(A)(t);
        return res;
    }
    else static if(is(T : Object))
        return obj.clone;
    else
        return obj;
}


/**
 * A dup operation returns a shallow copy of the given object.
 * All referenced objects are the same as the original, however
 * the returned object is not.
 *
 * All primitive types, structs and arrays are dupable.  Objects
 * are dupable if they implement a dup method.
 *
 * isDupable tests if a type can be duplicated.
 *
 * dup creates a shallow copy of a dupable type.
 */
template isDupable(T)
{
    static if (is(typeof(&T.dup)))
        enum { isDupable = true }
    else static if (is(T : Object))
        enum { isDupable = false }
    else
        enum { isDupable = true }
}



/**
 * Creates a shallow copy of the given object.
 * 
 * Params:
 *  t = The object we are copying.
 *
 * Returns:
 *  A shallow copy of the object.
 */
T dup(T)(T obj)
{
    static assert(isDupable!(T));
    
    static if(is(typeof(&T.dup)))
        return obj.dup;
    else
        return obj;
}




//Test cases
class DupMe
{
    this(int x)
    {
        this.x = x;
    }
    
    DupMe dup()
    {
        return new DupMe(x);
    }
    
    int x;
    
    char[] toString()
    {
        return format("%s", x);
    }
}

class CloneMe
{
    this(int x)
    {
        this.x = x;
    }
    
    CloneMe clone()
    {
        return new CloneMe(x);
    }
    
    int x;
    
    char[] toString()
    {
        return format("%s", x);
    }
}

class DontCloneMe
{
    this(int x)
    {
        this.x = x;
    }
    
    int x;
}

struct Test1
{
    int a, b, c;
}

void main()
{
    writefln("isCloneable!(int) = ", isCloneable!(int));
    writefln("isCloneable!(DontCloneMe) = ", isCloneable!(DontCloneMe));
    writefln("isCloneable!(CloneMe) = ", isCloneable!(CloneMe));
    writefln("isCloneable!(int*) = ", isCloneable!(int*));
    writefln("isCloneable!(int[]) = ", isCloneable!(int[]));
    writefln("isCloneable!(DontCloneMe[]) = ", isCloneable!(DontCloneMe[]));
    writefln("isCloneable!(CloneMe[]) = ", isCloneable!(CloneMe[]));
    writefln("isCloneable!(Test1) = ", isCloneable!(Test1));
    writefln("isCloneable!(DontCloneMe[][]) = ", isCloneable!(DontCloneMe[][]));
    writefln("isCloneable!(CloneMe[][]) = ", isCloneable!(CloneMe[][]));
    writefln("isCloneable!(int[5]) = ", isCloneable!(int[5]));
    
    CloneMe c1 = new CloneMe(19);
    CloneMe c2 = clone!(CloneMe)(c1);
    
    writefln("c1.x = %s, c2.x = %s", c1.toString, c2.toString);
    
    c2.x = 10000;
    writefln("c1.x = %s, c2.x = %s", c1.toString, c2.toString);
    
    
    CloneMe[] arr;
    arr ~= new CloneMe(1);
    arr ~= new CloneMe(2);
    arr ~= new CloneMe(3);
    arr ~= new CloneMe(4);
    arr ~= new CloneMe(5);
    arr ~= new CloneMe(6);
    
    CloneMe[] arr_clone = clone(arr);
    
    writefln("arr = %s\narr_clone = %s", arr, arr_clone);
    
    arr_clone[3].x = 10000;
    writefln("arr = %s\narr_clone = %s", arr, arr_clone);
    
    
    writefln("isDupable!(int) = ", isDupable!(int));
    writefln("isDupable!(DontCloneMe) = ", isDupable!(DontCloneMe));
    writefln("isDupable!(CloneMe) = ", isDupable!(CloneMe));
    writefln("isDupable!(DupMe) = ", isDupable!(DupMe));
    writefln("isDupable!(int*) = ", isDupable!(int*));
    writefln("isDupable!(int[]) = ", isDupable!(int[]));
    writefln("isDupable!(DontCloneMe[]) = ", isDupable!(DontCloneMe[]));
    writefln("isDupable!(CloneMe[]) = ", isDupable!(CloneMe[]));
    writefln("isDupable!(Test1) = ", isDupable!(Test1));
    writefln("isDupable!(DontCloneMe[][]) = ", isDupable!(DontCloneMe[][]));
    writefln("isDupable!(CloneMe[][]) = ", isDupable!(CloneMe[][]));
    writefln("isDupable!(int[5]) = ", isDupable!(int[5]));
    
    
    DupMe d1 = new DupMe(10);
    DupMe d2 = dup(d1);
    
    writefln("d1.x = %s, d2.x = %s", d1.toString, d2.toString);
    
    d2.x = 1000;
    writefln("d1.x = %s, d2.x = %s", d1.toString, d2.toString);
    
    DupMe[] darr;
    darr ~= new DupMe(1);
    darr ~= new DupMe(2);
    darr ~= new DupMe(3);
    DupMe[] darr_2 = dup(darr);
    
    writefln("darr = %s, darr2 = %s", darr, darr_2);
    
    darr_2[0].x = 100;
    darr_2 ~= new DupMe(20);
    
    writefln("darr = %s, darr2 = %s", darr, darr_2);
}
Aug 09 2006
next sibling parent kris <foo bar.com> writes:
Good stuff, Mikola ~ I'm with you on this. My only concern is the lack 
of a naming enforcement -- using compiler-supported operators instead 
(along with the appropriate opDup and opClone) would resolve that 
particular issue; but that's a reasonably minor detail, which could 
actually be implemented later on ...

Nice one!

- Kris


Mikola Lysenko wrote:
 Adding a virtual deep copy method to Object is a bad idea. Classes such as
 sockets or files must never be subjected to such a procedure, since the
 result would be unpredictable.
 
 A different solution is to require each type to explicitly state if it 
 supports deep-copies at compile time.  This can be done by creating the
 convention that all classes which support deep copy define a 'clone'
 method.  For the moment, clone needs to be implemented by hand, but given
 better introspection it should be possible to create a mixin which
 automatically performs this task.
 
 If everyone adheres to this convention, the following templates to allow
 anyone to test if a type is clonable at compile time - and easily perform
 a clone.  For completeness, there is also a shallow copy or 'dup'
 operation using the same technique.
 
 Code:
 
 import std.stdio, std.string;
 
 
 /**
  * A clone is a deep copy of an object.  It is totally independent
  * of the original object.  Once cloned, the original may be
  * deleted or modified without affecting the copy.
  *
  * All primitives types and structs are clonable by default - except
  * pointers.  Objects are clonable if and only if they define a 
  * clone method.
  *
  * isCloneable tests if a type can be cloned.
  *
  * clone makes a deep copy of the original object.
  */
 template isCloneable(T)
 {
     static if (is(T A : A[]))
         enum { isCloneable = isCloneable!(A) }
     else static if (is(typeof(&T.clone)))
         enum { isCloneable = true }
     else static if (is(T : Object))
         enum { isCloneable = false }
     else static if (is(T : T *))
         enum { isCloneable = false }
     else
         enum { isCloneable = true }
 }
 
 
 /**
  * Creates a deep copy of the given object.
  *
  * Params:
  *  t = The object we are cloning.
  *
  * Returns:
  *  A deep copy of the original object.
  */
 T clone(T)(T obj)
 {
     static assert (isCloneable!(T));
 
     static if(is(T A : A[]))
     {
         A[] res = new A[obj.length];    
         foreach(int i, inout A t; obj)
             res[i] = clone!(A)(t);
         return res;
     }
     else static if(is(T : Object))
         return obj.clone;
     else
         return obj;
 }
 
 
 /**
  * A dup operation returns a shallow copy of the given object.
  * All referenced objects are the same as the original, however
  * the returned object is not.
  *
  * All primitive types, structs and arrays are dupable.  Objects
  * are dupable if they implement a dup method.
  *
  * isDupable tests if a type can be duplicated.
  *
  * dup creates a shallow copy of a dupable type.
  */
 template isDupable(T)
 {
     static if (is(typeof(&T.dup)))
         enum { isDupable = true }
     else static if (is(T : Object))
         enum { isDupable = false }
     else
         enum { isDupable = true }
 }
 
 
 
 /**
  * Creates a shallow copy of the given object.
  * 
  * Params:
  *  t = The object we are copying.
  *
  * Returns:
  *  A shallow copy of the object.
  */
 T dup(T)(T obj)
 {
     static assert(isDupable!(T));
     
     static if(is(typeof(&T.dup)))
         return obj.dup;
     else
         return obj;
 }
 
 
 
 
 //Test cases
 class DupMe
 {
     this(int x)
     {
         this.x = x;
     }
     
     DupMe dup()
     {
         return new DupMe(x);
     }
     
     int x;
     
     char[] toString()
     {
         return format("%s", x);
     }
 }
 
 class CloneMe
 {
     this(int x)
     {
         this.x = x;
     }
     
     CloneMe clone()
     {
         return new CloneMe(x);
     }
     
     int x;
     
     char[] toString()
     {
         return format("%s", x);
     }
 }
 
 class DontCloneMe
 {
     this(int x)
     {
         this.x = x;
     }
     
     int x;
 }
 
 struct Test1
 {
     int a, b, c;
 }
 
 void main()
 {
     writefln("isCloneable!(int) = ", isCloneable!(int));
     writefln("isCloneable!(DontCloneMe) = ", isCloneable!(DontCloneMe));
     writefln("isCloneable!(CloneMe) = ", isCloneable!(CloneMe));
     writefln("isCloneable!(int*) = ", isCloneable!(int*));
     writefln("isCloneable!(int[]) = ", isCloneable!(int[]));
     writefln("isCloneable!(DontCloneMe[]) = ", isCloneable!(DontCloneMe[]));
     writefln("isCloneable!(CloneMe[]) = ", isCloneable!(CloneMe[]));
     writefln("isCloneable!(Test1) = ", isCloneable!(Test1));
     writefln("isCloneable!(DontCloneMe[][]) = ",
isCloneable!(DontCloneMe[][]));
     writefln("isCloneable!(CloneMe[][]) = ", isCloneable!(CloneMe[][]));
     writefln("isCloneable!(int[5]) = ", isCloneable!(int[5]));
     
     CloneMe c1 = new CloneMe(19);
     CloneMe c2 = clone!(CloneMe)(c1);
     
     writefln("c1.x = %s, c2.x = %s", c1.toString, c2.toString);
     
     c2.x = 10000;
     writefln("c1.x = %s, c2.x = %s", c1.toString, c2.toString);
     
     
     CloneMe[] arr;
     arr ~= new CloneMe(1);
     arr ~= new CloneMe(2);
     arr ~= new CloneMe(3);
     arr ~= new CloneMe(4);
     arr ~= new CloneMe(5);
     arr ~= new CloneMe(6);
     
     CloneMe[] arr_clone = clone(arr);
     
     writefln("arr = %s\narr_clone = %s", arr, arr_clone);
     
     arr_clone[3].x = 10000;
     writefln("arr = %s\narr_clone = %s", arr, arr_clone);
     
     
     writefln("isDupable!(int) = ", isDupable!(int));
     writefln("isDupable!(DontCloneMe) = ", isDupable!(DontCloneMe));
     writefln("isDupable!(CloneMe) = ", isDupable!(CloneMe));
     writefln("isDupable!(DupMe) = ", isDupable!(DupMe));
     writefln("isDupable!(int*) = ", isDupable!(int*));
     writefln("isDupable!(int[]) = ", isDupable!(int[]));
     writefln("isDupable!(DontCloneMe[]) = ", isDupable!(DontCloneMe[]));
     writefln("isDupable!(CloneMe[]) = ", isDupable!(CloneMe[]));
     writefln("isDupable!(Test1) = ", isDupable!(Test1));
     writefln("isDupable!(DontCloneMe[][]) = ", isDupable!(DontCloneMe[][]));
     writefln("isDupable!(CloneMe[][]) = ", isDupable!(CloneMe[][]));
     writefln("isDupable!(int[5]) = ", isDupable!(int[5]));
     
     
     DupMe d1 = new DupMe(10);
     DupMe d2 = dup(d1);
     
     writefln("d1.x = %s, d2.x = %s", d1.toString, d2.toString);
     
     d2.x = 1000;
     writefln("d1.x = %s, d2.x = %s", d1.toString, d2.toString);
     
     DupMe[] darr;
     darr ~= new DupMe(1);
     darr ~= new DupMe(2);
     darr ~= new DupMe(3);
     DupMe[] darr_2 = dup(darr);
     
     writefln("darr = %s, darr2 = %s", darr, darr_2);
     
     darr_2[0].x = 100;
     darr_2 ~= new DupMe(20);
     
     writefln("darr = %s, darr2 = %s", darr, darr_2);
 }
 
 

Aug 09 2006
prev sibling parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:

 Adding a virtual deep copy method to Object is a bad idea.

...
 A different solution is to require each type to explicitly state if it 
 supports deep-copies at compile time.

 If everyone adheres to this convention, the following templates to allow
 anyone to test if a type is clonable at compile time - and easily perform
 a clone.  

...
 For completeness, there is also a shallow copy or 'dup'
 operation using the same technique.

Yes. This is most of what I was trying to get across. The only problem is the phrase "If everyone adheres to this convention". That will never happen, people being as they are. This is why I'd like these capabilities to be supported by the compiler via the use of operators that invoke the associated 'op' function. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 10/08/2006 4:31:55 PM
Aug 09 2006
next sibling parent kris <foo bar.com> writes:
Derek Parnell wrote:
 On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:
 
 
Adding a virtual deep copy method to Object is a bad idea.

...
A different solution is to require each type to explicitly state if it 
supports deep-copies at compile time.

...
If everyone adheres to this convention, the following templates to allow
anyone to test if a type is clonable at compile time - and easily perform
a clone.  

...
For completeness, there is also a shallow copy or 'dup'
operation using the same technique.

Yes. This is most of what I was trying to get across. The only problem is the phrase "If everyone adheres to this convention". That will never happen, people being as they are. This is why I'd like these capabilities to be supported by the compiler via the use of operators that invoke the associated 'op' function.

Yes; although "we", as a group, /could/ commandeer the opDup() and opClone() method-names ourselves ~ it's surprising how having the op-prefix can persuade people to comply with a convention, especially when there's some potential that the compiler may catch up later :) If we did start using these names, how might it conflict? Would opDup potentially mean something different in the future? Or opClone? What doth Walter say?
Aug 09 2006
prev sibling next sibling parent reply kris <foo bar.com> writes:
Derek Parnell wrote:
 On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:
 
 
Adding a virtual deep copy method to Object is a bad idea.

...
A different solution is to require each type to explicitly state if it 
supports deep-copies at compile time.

...
If everyone adheres to this convention, the following templates to allow
anyone to test if a type is clonable at compile time - and easily perform
a clone.  

...
For completeness, there is also a shallow copy or 'dup'
operation using the same technique.

Yes. This is most of what I was trying to get across. The only problem is the phrase "If everyone adheres to this convention". That will never happen, people being as they are. This is why I'd like these capabilities to be supported by the compiler via the use of operators that invoke the associated 'op' function.

Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?
Aug 10 2006
parent reply kris <foo bar.com> writes:
kris wrote:
 Derek Parnell wrote:
 
 On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:


 Adding a virtual deep copy method to Object is a bad idea.

...
 A different solution is to require each type to explicitly state if 
 it supports deep-copies at compile time.

...
 If everyone adheres to this convention, the following templates to allow
 anyone to test if a type is clonable at compile time - and easily 
 perform
 a clone.  

...
 For completeness, there is also a shallow copy or 'dup'
 operation using the same technique.

Yes. This is most of what I was trying to get across. The only problem is the phrase "If everyone adheres to this convention". That will never happen, people being as they are. This is why I'd like these capabilities to be supported by the compiler via the use of operators that invoke the associated 'op' function.

Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?

Perhaps better to use properties instead of operators? Thus, x.dup; would invoke the opDup() method where appropriate (and error if not supported), and x.clone; would invoke opClone()? At least that would be compatible with current .dup conventions, and avoid introducing disputable symbolic operators? Otherwise, we might end up with smiley's as operators :) It wouldn't be entirely necessary, but perhaps clone, like dup, might be supported for native-types directly (int, char*[], etc)? For the sake of consistency?
Aug 10 2006
parent Dave <Dave_member pathlink.com> writes:
kris wrote:
 kris wrote:
 Derek Parnell wrote:

 On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:


 Adding a virtual deep copy method to Object is a bad idea.

...
 A different solution is to require each type to explicitly state if 
 it supports deep-copies at compile time.

...
 If everyone adheres to this convention, the following templates to 
 allow
 anyone to test if a type is clonable at compile time - and easily 
 perform
 a clone.  

...
 For completeness, there is also a shallow copy or 'dup'
 operation using the same technique.

Yes. This is most of what I was trying to get across. The only problem is the phrase "If everyone adheres to this convention". That will never happen, people being as they are. This is why I'd like these capabilities to be supported by the compiler via the use of operators that invoke the associated 'op' function.

Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?

Perhaps better to use properties instead of operators? Thus, x.dup; would invoke the opDup() method where appropriate (and error if not supported), and x.clone; would invoke opClone()? At least that would be compatible with current .dup conventions, and avoid introducing disputable symbolic operators? Otherwise, we might end up with smiley's as operators :) It wouldn't be entirely necessary, but perhaps clone, like dup, might be supported for native-types directly (int, char*[], etc)? For the sake of consistency?

I would agree - it'd be important for templates also.
Aug 10 2006
prev sibling parent Mikola Lysenko <mclysenk mtu.edu> writes:
On Thu, 10 Aug 2006 16:36:04 +1000, Derek Parnell wrote:
 The only problem is the phrase "If everyone adheres to this convention".
 That will never happen, people being as they are. This is why I'd like
 these capabilities to be supported by the compiler via the use of operators
 that invoke the associated 'op' function.

The problem is that a new operator doesn't really solve anything. There is no way for the compiler to strictly enforce that 'opClone' performs a clone, much as it can not check that 'opAdd' performs an addition. Adding new operators is hardly a guarantee that programmers will use them sensibly, and it seems unnecessary given the current property syntax is equivalent. A convention might seem a bit weak, but it has worked successfully in the past. Consider C++'s copy constructor and operator= ; neither have any guarantee that they will act as intended. It is the responsibility of the programmer alone to ensure they are correct. However, it is not very difficult to correctly implement and verify these sorts of methods, it should not create much of a burden.
Aug 10 2006
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeirosATgmail SPAM.com> writes:
Derek Parnell wrote:
 
 And maybe one day (hoping against precedent) that Walter will actually see
 that an operator for copying stuff is not such a stupid idea.
 
    auto backup := q; // invokes q.onCopy() if it exists.
 

What's the sense of having a binary operator for an unary operation? Clearly it would have to be unary like ":foo" suggested elsewhere or " foo" or whatever. But would it be worth it? I don't think so, I think the gain in syntactic sugar is not worth adding an operator for this function. More on that, is commented after the Hasan's - Derek's exchange below. For me, the operator := would be useful, but as a proper copy operator, a binary operator, which would copy the contents of the right side operand to the left side one. The difference from the proposed: auto backup := q; // invokes q.onCopy() if it exists. is that the identity of backup is changed as it is assigned to a new object. Under the binary version, the actual contents of the left-side instance ("backup" in that example) are changed. This would allow, among other things, to work with reference types as if they were value types, which I think would be useful in many scenarios. Like, for example, in a code that uses struct variables and struct copying, changing the struct vars types from struct values to struct pointers. Or changing the type of a var from int, to BigNum, a hypothetical integer class of unlimited precision. Another use case is to be able to copy structs whose *abstract-state* is more than just the "shallow" value copied by a shallow copy. That is, if you have structs that have references to data that are part of the struct's abstract-state, then merely copying the struct value (using the assign operator) won't work, as the assign operator does a shallow copy in structs, which won't result in a correct(complete) copy. Also, a copy operator would supersede the current awkward and "special-case" syntax of Array Copying and Array Setting: int[3] s; int[3] t; s[] = t; // the 3 elements of t[3] are copied into s[3] s[] = t[]; // the 3 elements of t[3] are copied into s[3] int[3] s; int* p; s[] = 3; // same as s[0] = 3, s[1] = 3, s[2] = 3 p[0..2] = 3; // same as p[0] = 3, p[1] = 3 Instead, those would become respectively: s := t; s := t; s := 3; p[0..2] := 3; Derek wrote:
 On Thu, 03 Aug 2006 17:12:39 -0600, Hasan Aljudy wrote:

 why an operator?
 a method/property is more suitable, I think.

Where does this train of thought stop? Why an operator for anything?

 need '=' '>=' '+=' etc... when we have all those useful opXXX functions
 handy? Of course we do, because it makes coding easier to read and write.

 The action of cloning an item is quite a common action and having to 

"Where does this train of thought stop? Why an operator for anything? " I can turn that question around, why not an operator for other operations like new or delete? Wouldn't it make coding easier to read and write?: auto foo = #Foo(); // new Foo() foo; // delete foo *shivers*... So we can't have a sweeping, generalizing idea stating if it's worth or not to have an operator, or else we would have D as APL (operator abuse) or SmallTalk (almost no operators). Each case has to be considered to see if it's worth it. For dup I don't think it is: For starters, some of the advantages of having operators are the ease of use from being able to use infix notation and predefined operator precedence, which is only relevant for binary ops and not dup. Second, from looking at dup's frequency of use (often but not that often), complexity of it's operation (more complex operations should be more verbose IMO), and gain in syntactic sugar (minimal, both in typed characters as well as form). And I don't see any other advantages in having a dup operator. (note the next comment)
 method name is not as convenient as an operator. Also, an operator 

 with objects, structs, arrays, and basic-types where as method names 

 work so well with all types. This simplifies template construction.

I don't see the problem here, a templated free function should work as well for any kind of type (like the incomplete one I mentioned elsewhere). (If a method can and/or should be used instead of a free function, well that's another problem altogether.) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Aug 12 2006
parent Derek Parnell <derek psyc.ward> writes:
 Derek Parnell wrote:

... a whole lot of wasted bandwith that is never going to happen anyway so who gives a damn about arguing over the details. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Aug 13 2006
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Those of you who participated / care about this discussion on copying:

I created a skeletal page for consolidating the arguments made in this 
thread:
http://www.prowiki.org/wiki4d/wiki.cgi?FeatureRequestList/CopyOperator

Please feel free to flesh it out a bit more.

--bb

Derek Parnell wrote:
 Currently there doesn't seem to be any standard D mechanism (read:
 operator) to take a copy of an object. So are there any suggestions for a
 name that we can all agree on; one that might become an unofficial
 standard? 
 
 For arrays we have the 'dup' property but for objects there is nothing that
 the compiler assumes. I'm partial to 'onDup' or 'onCopy', and maybe even a
 'onDeepCopy' as an additional function.
 
 Example:
 
   class Foo
   {
       int x;
       Bar b;
 
       this(int y) 
       {
            x = y;
            b = new Bar(y);
       }
 
       Foo onCopy()
       {
           Foo t;
           t = new Foo(x);
           return t;
        }
    }
 
    . . . 
 
    auto backup = q.onCopy();
 
 And maybe one day (hoping against precedent) that Walter will actually see
 that an operator for copying stuff is not such a stupid idea.
 
    auto backup := q; // invokes q.onCopy() if it exists.
 

Oct 24 2006