digitalmars.D - Taking a copy of an object
- Derek Parnell (35/35) Aug 03 2006 Currently there doesn't seem to be any standard D mechanism (read:
- Hasan Aljudy (2/41) Aug 03 2006 a compiler generated .dup method would be nice.
- Tom S (2/4) Aug 03 2006 Reflection and the ability to generate your own would be even better.
- Hasan Aljudy (3/11) Aug 03 2006 well you already can create your own .dup
- Tom S (7/21) Aug 03 2006 There was a subtle difference in what I wrote :) 'generate' vs 'create'
- Hasan Aljudy (3/32) Aug 03 2006 Sorry, what's the difference of writing code and "generating code by
- Tom S (12/47) Aug 03 2006 I didn't write 'generating code by yourself'. Anyway, in this context:
- Lionello Lunesu (13/21) Aug 03 2006 What's stopping you from using "dup" as the name?
- Bruno Medeiros (20/59) Aug 03 2006 What's the "on" prefix for? I think the name should be something like:
- Hasan Aljudy (3/14) Aug 03 2006 Oh please, I hate the := operator, it's too ugly.
- Derek (20/35) Aug 03 2006 I don't give a damn what operator is used, this was *JUST AN EXAMPLE*.
- Hasan Aljudy (3/47) Aug 03 2006 why an operator?
- Derek (12/14) Aug 03 2006 Where does this train of thought stop? Why an operator for anything? Do ...
- Kirk McDonald (25/78) Aug 03 2006 People used to C++ are used to doing this with an operator overload.
- Derek Parnell (26/50) Aug 03 2006 Copy constructors and 'standard' functions would have to work with basic
- Kirk McDonald (41/97) Aug 03 2006 opDup appeals to me, but more consistent would probably be a standard
- Derek Parnell (47/89) Aug 03 2006 Agreed, but I'm not really fussed.
- Kirk McDonald (41/86) Aug 04 2006 Do we want this to mean a deep copy? The only distinction we (I?) have
- kris (15/31) Aug 03 2006 yeah :)
- Derek Parnell (13/17) Aug 04 2006 I'm not asking for a default deep copy. If you haven't defined one then ...
- kris (14/28) Aug 04 2006 True. If I have an array of char*, an array of class refs, or something
- Dave (25/62) Aug 04 2006 With all that in mind - if .dup was given an op overload for classes and...
- kris (3/77) Aug 04 2006 The issue I see, mixing deep & shallow copy like this, is that misuse
- Dave (5/86) Aug 04 2006 Yea that's a drawback. Just trying to figure out how things could be don...
- kris (10/106) Aug 04 2006 Aye. But does it cover Derek's concern of deep-copy for arrays and so
- Dave (14/123) Aug 04 2006 I would say - everytime I've seen 'deep' copies done on the elements of ...
- Bruno Medeiros (16/20) Aug 08 2006 There is no need for casting. Since D supports covariant return types,
- kris (11/34) Aug 08 2006 Yes, we're well aware of the covariance aspect. However, we'd been
- Bruno Medeiros (5/44) Aug 08 2006 Hum, you're right, I thought you were talking about deep copy.
- Bruno Medeiros (40/62) Aug 08 2006 I've just realized a little nuance that both I and the rest of us are
- kris (3/74) Aug 08 2006 Speak for yourself, Bruno: all of this is simply taken for granted in
- Bruno Medeiros (15/59) Aug 08 2006 I was writing a reply in how that was not so, and people where blending
- Derek (12/63) Aug 03 2006 The 'on' prefix is a *hint* to Walter that I'd really like this function...
- Tom S (2/43) Aug 03 2006 Somehow, 'on' doesn't sound like an operator. On the other hand 'op' doe...
- Hasan Aljudy (4/55) Aug 03 2006 I think he meant op ..
- Derek (6/7) Aug 03 2006 LOL...my mistake. I've been coding too much in another language recently...
- Bruno Medeiros (9/25) Aug 08 2006 I quite agree with what you said, I misstated my comments: when I said
- Mikola Lysenko (230/230) Aug 09 2006 Adding a virtual deep copy method to Object is a bad idea. Classes such ...
- kris (8/262) Aug 09 2006 Good stuff, Mikola ~ I'm with you on this. My only concern is the lack
- Derek Parnell (16/24) Aug 09 2006 ...
- kris (8/41) Aug 09 2006 Yes; although "we", as a group, /could/ commandeer the opDup() and
- kris (3/36) Aug 10 2006 Somewhat tongue-in-cheek: I guess if the dup operator were to become
- kris (10/54) Aug 10 2006 Perhaps better to use properties instead of operators? Thus, x.dup;
- Dave (2/61) Aug 10 2006 I would agree - it'd be important for templates also.
- Mikola Lysenko (13/17) Aug 10 2006 The problem is that a new operator doesn't really solve anything. There
- Bruno Medeiros (73/89) Aug 12 2006 What's the sense of having a binary operator for an unary operation?
- Derek Parnell (6/7) Aug 13 2006 ... a whole lot of wasted bandwith that is never going to happen anyway ...
- Bill Baxter (7/46) Oct 24 2006 Those of you who participated / care about this discussion on copying:
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
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
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
Tom S wrote:Hasan Aljudy wrote:well you already can create your own .dup I mean it's just a method that returns typeof(this)a compiler generated .dup method would be nice.Reflection and the ability to generate your own would be even better.
Aug 03 2006
Hasan Aljudy wrote:Tom S wrote: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 StachowiakHasan Aljudy wrote:well you already can create your own .dup I mean it's just a method that returns typeof(this)a compiler generated .dup method would be nice.Reflection and the ability to generate your own would be even better.
Aug 03 2006
Tom S wrote:Hasan Aljudy wrote:Sorry, what's the difference of writing code and "generating code by yourself"?Tom S wrote: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 StachowiakHasan Aljudy wrote:well you already can create your own .dup I mean it's just a method that returns typeof(this)a compiler generated .dup method would be nice.Reflection and the ability to generate your own would be even better.
Aug 03 2006
Hasan Aljudy wrote:Tom S wrote: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 StachowiakHasan Aljudy wrote:Sorry, what's the difference of writing code and "generating code by yourself"?Tom S wrote: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 StachowiakHasan Aljudy wrote:well you already can create your own .dup I mean it's just a method that returns typeof(this)a compiler generated .dup method would be nice.Reflection and the ability to generate your own would be even better.
Aug 03 2006
"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 { #void main() { L.
Aug 03 2006
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
Bruno Medeiros wrote:Derek Parnell wrote:<Snip>Oh please, I hate the := operator, it's too ugly.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.
Aug 03 2006
On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:Bruno Medeiros wrote: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!"Derek Parnell wrote:<Snip>Oh please, I hate the := operator, it's too ugly.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.
Aug 03 2006
Derek wrote:On Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:why an operator? a method/property is more suitable, I think.Bruno Medeiros wrote: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 wrote:<Snip>Oh please, I hate the := operator, it's too ugly.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.
Aug 03 2006
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
Hasan Aljudy wrote:Derek 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.) 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/wikiOn Thu, 03 Aug 2006 14:12:03 -0600, Hasan Aljudy wrote:why an operator? a method/property is more suitable, I think.Bruno Medeiros wrote: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 wrote:<Snip>Oh please, I hate the := operator, it's too ugly.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.
Aug 03 2006
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
Derek Parnell wrote:On Thu, 03 Aug 2006 16:28:25 -0700, Kirk McDonald wrote:Of course. :-)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.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/wikiclass 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);
Aug 03 2006
On Thu, 03 Aug 2006 23:19:23 -0700, Kirk McDonald wrote:opDup appeals to meMe 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 functionHow 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 constructorOk, whatever.arrays/AAs: dup propertyNah ... needs a 'copy constructor' too, I think.structs,Nah ... needs a 'copy constructor' too, I think.primitive types, etc: by-value copyOk.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
Derek Parnell wrote:On Thu, 03 Aug 2006 23:19:23 -0700, Kirk McDonald wrote:"Item" it is!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.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/wikiWe 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.
Aug 04 2006
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: I don't see any point of introducing obtuse operators when consistency would dictate something like this: 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
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
Derek Parnell wrote:On Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.
Aug 04 2006
kris wrote:Derek Parnell wrote: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; } } - DaveOn Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.
Aug 04 2006
Dave wrote:kris wrote: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?Derek Parnell wrote: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; } } - DaveOn Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.
Aug 04 2006
kris wrote:Dave wrote: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.kris wrote: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?Derek Parnell wrote: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; } } - DaveOn Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.
Aug 04 2006
Dave wrote:kris wrote: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?Dave wrote: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.kris wrote: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?Derek Parnell wrote: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; } } - DaveOn Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.
Aug 04 2006
kris wrote:Dave wrote:Nope <g>kris wrote:Aye. But does it cover Derek's concern of deep-copy for arrays and soDave wrote: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.kris wrote: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?Derek Parnell wrote: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; } } - DaveOn Thu, 03 Aug 2006 23:47:47 -0700, kris wrote: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 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 :)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.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
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
Bruno Medeiros wrote:kris wrote: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?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(); } }
Aug 08 2006
kris wrote:Bruno Medeiros wrote: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#Dkris wrote: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?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(); } }
Aug 08 2006
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
Bruno Medeiros wrote:Derek wrote:Speak for yourself, Bruno: all of this is simply taken for granted in some of the other posts.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.
Aug 08 2006
kris wrote:Bruno Medeiros wrote: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: [...]Derek wrote:Speak for yourself, Bruno: all of this is simply taken for granted in some of the other posts.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.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
On Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:Derek Parnell wrote: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.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.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
Derek wrote:On Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:Somehow, 'on' doesn't sound like an operator. On the other hand 'op' does...Derek Parnell wrote: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.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:
Aug 03 2006
Tom S wrote:Derek wrote: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 onXxxxOn Thu, 03 Aug 2006 14:26:08 +0100, Bruno Medeiros wrote:Somehow, 'on' doesn't sound like an operator. On the other hand 'op' does...Derek Parnell wrote: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.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:
Aug 03 2006
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
Derek wrote: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#DAlso, 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.
Aug 08 2006
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
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
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
Derek Parnell wrote:On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote: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?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.
Aug 09 2006
Derek Parnell wrote:On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?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.
Aug 10 2006
kris wrote:Derek Parnell wrote: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?On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?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.
Aug 10 2006
kris wrote:kris wrote:I would agree - it'd be important for templates also.Derek Parnell wrote: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?On Thu, 10 Aug 2006 00:30:15 -0400, Mikola Lysenko wrote:Somewhat tongue-in-cheek: I guess if the dup operator were to become ":=" then clone would be "::=" ?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.
Aug 10 2006
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
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:Do wewhy 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 touse a "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 operatorcan actwith objects, structs, arrays, and basic-types where as method namesdon'twork 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
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
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