September 15, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Oskar Linde | On Fri, 15 Sep 2006 09:57:53 +0200, Oskar Linde wrote: > Georg Wrede wrote: >> Hasan Aljudy wrote: >>> Georg Wrede wrote: >>> >>>> Overloading of the assignment operator is not allowed in D. >>>> >>>> But no problem, we can do it right now, in spite of it. >>>> >>>> Just overload the opCatAssign operator instead, and use ~= where = would be used. >>>> >>>> This way we might gather enough use cases to really know whether it is good or bad in practice. >>> >>> <snip> >>> >>> Why do you have to think in C++ when coding in D? >> >> I don't. Do you? >> >> Seriously, if you look back in the archives, I've been pretty voluminous in my support of several ideas and opinions. Getting assignment operator overload hasn't been one of them. >> >> Then again, some other people have really wanted it, and I stumbled on a method to try it out with, which I wrote here. Now they can try it out, without Walter having to make changes to the language. > > There is more to it than having an operator to overload. You want to be able to overload both assignment and copying. > > Given > > struct T { ... opCatAssign(T t) {...} } > void func(T t) {...} > T a,b; > > You take care of > > a ~= b; Yes, with 'a.opCatAssign(b);' > but not > > func(b); > > where a copy is created too. Are you saying that a simple struct reference in a function call just does a shallow copy of the struct, but that sometimes you might need to do a deep copy instead? What about ... func( T x := b); assuming for the sake of this example that ':=' is the (deep) copy operator? -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 15/09/2006 6:06:49 PM |
September 16, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek Parnell |
Derek Parnell wrote:
> On Fri, 15 Sep 2006 09:57:53 +0200, Oskar Linde wrote:
>
>> Georg Wrede wrote:
>>> Hasan Aljudy wrote:
>>>> Georg Wrede wrote:
>>>>
>>>>> Overloading of the assignment operator is not allowed in D.
>>>>>
>>>>> But no problem, we can do it right now, in spite of it.
>>>>>
>>>>> Just overload the opCatAssign operator instead, and use ~= where = would be used.
>>>>>
>>>>> This way we might gather enough use cases to really know whether it is good or bad in practice.
>>>> <snip>
>>>>
>>>> Why do you have to think in C++ when coding in D?
>>> I don't. Do you?
>>>
>>> Seriously, if you look back in the archives, I've been pretty voluminous in my support of several ideas and opinions. Getting assignment operator overload hasn't been one of them.
>>>
>>> Then again, some other people have really wanted it, and I stumbled on a method to try it out with, which I wrote here. Now they can try it out, without Walter having to make changes to the language.
>> There is more to it than having an operator to overload. You want to be able to overload both assignment and copying.
>>
>> Given
>>
>> struct T { ... opCatAssign(T t) {...} }
>> void func(T t) {...}
>> T a,b;
>>
>> You take care of
>>
>> a ~= b;
>
> Yes, with 'a.opCatAssign(b);'
>
>> but not
>>
>> func(b);
>>
>> where a copy is created too.
>
> Are you saying that a simple struct reference in a function call just does
> a shallow copy of the struct, but that sometimes you might need to do a
> deep copy instead?
>
> What about ...
>
> func( T x := b);
>
> assuming for the sake of this example that ':=' is the (deep) copy
> operator?
>
I vote:
No for copy operators.
Specially no for the ugly and cumbersome-to-type := operator.
Yes for auto-generated copy methods/properties. (both deep and shallow)
T x = b.dup.deep;
T y = b.dup.shallow;
|
September 16, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hasan Aljudy | On Fri, 15 Sep 2006 20:19:48 -0600, Hasan Aljudy wrote: > Derek Parnell wrote: >> On Fri, 15 Sep 2006 09:57:53 +0200, Oskar Linde wrote: >> >>> Georg Wrede wrote: >>>> Hasan Aljudy wrote: >>>>> Georg Wrede wrote: >>>>> >>>>>> Overloading of the assignment operator is not allowed in D. >>>>>> >>>>>> But no problem, we can do it right now, in spite of it. >>>>>> >>>>>> Just overload the opCatAssign operator instead, and use ~= where = would be used. >>>>>> >>>>>> This way we might gather enough use cases to really know whether it is good or bad in practice. >>>>> <snip> >>>>> >>>>> Why do you have to think in C++ when coding in D? >>>> I don't. Do you? >>>> >>>> Seriously, if you look back in the archives, I've been pretty voluminous in my support of several ideas and opinions. Getting assignment operator overload hasn't been one of them. >>>> >>>> Then again, some other people have really wanted it, and I stumbled on a method to try it out with, which I wrote here. Now they can try it out, without Walter having to make changes to the language. >>> There is more to it than having an operator to overload. You want to be able to overload both assignment and copying. >>> >>> Given >>> >>> struct T { ... opCatAssign(T t) {...} } >>> void func(T t) {...} >>> T a,b; >>> >>> You take care of >>> >>> a ~= b; >> >> Yes, with 'a.opCatAssign(b);' >> >>> but not >>> >>> func(b); >>> >>> where a copy is created too. >> >> Are you saying that a simple struct reference in a function call just does a shallow copy of the struct, but that sometimes you might need to do a deep copy instead? >> >> What about ... >> >> func( T x := b); >> >> assuming for the sake of this example that ':=' is the (deep) copy >> operator? >> > > I vote: > No for copy operators. > Specially no for the ugly and cumbersome-to-type := operator. > > Yes for auto-generated copy methods/properties. (both deep and shallow) > > T x = b.dup.deep; > T y = b.dup.shallow; Oh I see ... ":=" is obviously more ugly and more cumbersome than ".dup.deep". Don't know how I didn't see that. And we would implemented as ???? class Foo { Foo dup() { Foo deep() { ... } Foo shallow() { ... } } } Amazingly simple, no? On second thoughts, no thank you. -- Derek Parnell Melbourne, Australia "Down with mediocrity!" |
September 16, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Hasan Aljudy | Hasan Aljudy wrote:
>
> I vote:
> No for copy operators.
> Specially no for the ugly and cumbersome-to-type := operator.
>
> Yes for auto-generated copy methods/properties. (both deep and shallow)
>
> T x = b.dup.deep;
> T y = b.dup.shallow;
The only problem with this is that you can't have a compiler-generated deep copy without taking on some serious consequences and/or risks. IMO, that's too much effort for a compiler author, for a feature that is so limited in use and scope.
Take this guy for example:
class TreeNode{
TreeNode parent;
TreeNode[] children;
}
What about cyclic references in networks of objects (.parent in above)? You'd have to have some kind of monitor that keeps track of all the references consumed by the dup.deep() process, just to avoid cycles. Either it's an Object field that flags its status during a dup() or a massive array/map that keeps log of every object touched - either one can amount to some very serious space/time overhead.
A stub deep copy, one that lives on Object, isn't possible either since D doesn't have the reflection mojo to pull it off. Even if it did, would you really want to generate a deep copy of an object network completely via reflection? It'd be painfully slow.
Invariably, a custom-coded clone() or dup() of some kind that allows for deep copying on request is the best approach - take a look at how other languages (e.g. Java) shy away from implementing a deep copy directly into the language.
class TreeNode{
TreeNode parent;
TreeNode[] children;
TreeNode clone(TreeNode copyParent){
TreeNode copy = new TreeNode();
foreach(child; this.children){
copy.children ~= child.clone(copy);
}
copy.parent = copyParent;
return copy;
}
}
What's wrong with doing things like this?
Now, I do think that providing a shallow-copy, dup(), as a member of Object is a no-brainer. You can easily do this at the binary level via memcopy with little to no effort, and no real side-effects. Plus it would make the current schism between objects and arrays a little less obvious (that is, make templates easier to code).
|
September 16, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Derek Parnell | Derek Parnell wrote: > On Fri, 15 Sep 2006 20:19:48 -0600, Hasan Aljudy wrote: > >> Derek Parnell wrote: >>> On Fri, 15 Sep 2006 09:57:53 +0200, Oskar Linde wrote: >>> >>>> Georg Wrede wrote: >>>>> Hasan Aljudy wrote: >>>>>> Georg Wrede wrote: >>>>>> >>>>>>> Overloading of the assignment operator is not allowed in D. >>>>>>> >>>>>>> But no problem, we can do it right now, in spite of it. >>>>>>> >>>>>>> Just overload the opCatAssign operator instead, and use ~= where = would be used. >>>>>>> >>>>>>> This way we might gather enough use cases to really know whether it is good or bad in practice. >>>>>> <snip> >>>>>> >>>>>> Why do you have to think in C++ when coding in D? >>>>> I don't. Do you? >>>>> >>>>> Seriously, if you look back in the archives, I've been pretty voluminous in my support of several ideas and opinions. Getting assignment operator overload hasn't been one of them. >>>>> >>>>> Then again, some other people have really wanted it, and I stumbled on a method to try it out with, which I wrote here. Now they can try it out, without Walter having to make changes to the language. >>>> There is more to it than having an operator to overload. You want to be able to overload both assignment and copying. >>>> >>>> Given >>>> >>>> struct T { ... opCatAssign(T t) {...} } >>>> void func(T t) {...} >>>> T a,b; >>>> >>>> You take care of >>>> >>>> a ~= b; >>> Yes, with 'a.opCatAssign(b);' >>> >>>> but not >>>> >>>> func(b); >>>> >>>> where a copy is created too. >>> Are you saying that a simple struct reference in a function call just does >>> a shallow copy of the struct, but that sometimes you might need to do a >>> deep copy instead? >>> >>> What about ... >>> >>> func( T x := b); >>> >>> assuming for the sake of this example that ':=' is the (deep) copy >>> operator? >>> >> I vote: >> No for copy operators. >> Specially no for the ugly and cumbersome-to-type := operator. >> >> Yes for auto-generated copy methods/properties. (both deep and shallow) >> >> T x = b.dup.deep; >> T y = b.dup.shallow; > > Oh I see ... ":=" is obviously more ugly and more cumbersome than > ".dup.deep". Don't know how I didn't see that. Of course it's more ugly, and yes, it's more combuersome to type, even though it looks "shorter". Typing := involves pressing "shift" and also involves pressing a button that's a bit too far away from one's fingers. > > And we would implemented as ???? I think that's not possible in D right now, but maybe if there was something like: class Foo { namespace dup //or scope dup{ .... } { Foo deep() { ... } Foo shallow() { ... } } } > > class Foo > { > Foo dup() > { > Foo deep() > { ... } > > Foo shallow() > { ... } > } > } > > Amazingly simple, no? No, it's not. > > On second thoughts, no thank you. > You're welcome. |
September 16, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | pragma wrote: > Hasan Aljudy wrote: >> >> I vote: >> No for copy operators. >> Specially no for the ugly and cumbersome-to-type := operator. >> >> Yes for auto-generated copy methods/properties. (both deep and shallow) >> >> T x = b.dup.deep; >> T y = b.dup.shallow; > > The only problem with this is that you can't have a compiler-generated deep copy without taking on some serious consequences and/or risks. IMO, that's too much effort for a compiler author, for a feature that is so limited in use and scope. > > Take this guy for example: > > class TreeNode{ > TreeNode parent; > TreeNode[] children; > } > > What about cyclic references in networks of objects (.parent in above)? You'd have to have some kind of monitor that keeps track of all the references consumed by the dup.deep() process, just to avoid cycles. Either it's an Object field that flags its status during a dup() or a massive array/map that keeps log of every object touched - either one can amount to some very serious space/time overhead. > > A stub deep copy, one that lives on Object, isn't possible either since D doesn't have the reflection mojo to pull it off. Even if it did, would you really want to generate a deep copy of an object network completely via reflection? It'd be painfully slow. > > Invariably, a custom-coded clone() or dup() of some kind that allows for deep copying on request is the best approach - take a look at how other languages (e.g. Java) shy away from implementing a deep copy directly into the language. > > class TreeNode{ > TreeNode parent; > TreeNode[] children; > > TreeNode clone(TreeNode copyParent){ > TreeNode copy = new TreeNode(); > foreach(child; this.children){ > copy.children ~= child.clone(copy); > } > copy.parent = copyParent; > return copy; > } > } > > What's wrong with doing things like this? I actually never thought about the problem. Thanks for clearing things out. > > Now, I do think that providing a shallow-copy, dup(), as a member of Object is a no-brainer. You can easily do this at the binary level via memcopy with little to no effort, and no real side-effects. Plus it would make the current schism between objects and arrays a little less obvious (that is, make templates easier to code). |
September 22, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > Georg Wrede wrote: >> Overloading of the assignment operator is not allowed in D. > > Overloading the assignment operator in a language where objects are manipulated through references would be a bit weird, wouldn't it? It would almost require the creation of a new assignment operator meant specifically for copy semantics, similar to how we have '==' and 'is' for identity vs. equality comparisons. > > > Sean That might be just the right thing to do (to have a copy operator), just as we have those two comparison operators. One possible prominent advantage, in terms of things that Walter likes, (but that others such as me and others don't care that much about) is: ease of porting from C++ to D. Whereas a 'pointer to C++ class' translates easily and directly into a 'D class', the same is not for a 'C++ class', because it is a value type. If the C++ class doesn't use inheritance you might just get away with porting it to a D struct, but that likely won't be the case. You will have to make a translation that is not direct, and thus bothersome and/or error-prone. Having such a copy operator would allow for a direct translation, I think. One must be wary of what Oskar mentioned: that the assignment operator is not the only assignment, there is also the implicit assignment of a function call's argument passing. I think this can be easily solved by having the function call use the copy operator, if it is overloaded, for argument creation. Hum.., now that this is mentioned, how does it work in C++? Does C++ do it that way? -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
September 22, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | pragma wrote: > Hasan Aljudy wrote: >> >> I vote: >> No for copy operators. >> Specially no for the ugly and cumbersome-to-type := operator. >> >> Yes for auto-generated copy methods/properties. (both deep and shallow) >> >> T x = b.dup.deep; >> T y = b.dup.shallow; > > The only problem with this is that you can't have a compiler-generated deep copy without taking on some serious consequences and/or risks. IMO, that's too much effort for a compiler author, for a feature that is so limited in use and scope. > I don't think you cave have a compiler-generated deep copy, *at all*. At least for the proper notion of "deep copy". When one speaks of a clone method, or of a "deep copy", what one means (or at least *should* mean), is a copy of the "abstract state" of the object. A *conceptual* copy of the the object. Such "abstract state" might not coincide with the set of *all* objects/members that can be reached recursively from the target object. There might be members that are simply not part of the object's abstract state. For example, consider some GUI Button widget class that has a member which is a reference to it's parent widget. If I want to clone/deep-copy this Button widget, should it clone it's parent widget too, and possibly the whole encompassing window? Similar example: a Shape class, which would have a list of vertexes, color, position and a reference to a Renderer which is used for drawing. When a Shape is cloned, should all members be cloned, in particular the Renderer member as well? Likely not, because it is not part of the abstract state of Shape. This notion of abstract state was actually picked up in that paper about Javari (immutability for Java), as some might have noticed. ;) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D |
September 22, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote:
>
> One must be wary of what Oskar mentioned: that the assignment operator is not the only assignment, there is also the implicit assignment of a function call's argument passing. I think this can be easily solved by having the function call use the copy operator, if it is overloaded, for argument creation. Hum.., now that this is mentioned, how does it work in C++? Does C++ do it that way?
Pretty much. For example:
class C
{
public:
C(int i) : x(i) {}
C(C const& o) : x(0) {}
int x;
};
void f1(C val) { printf("%d\n", val.x); }
void f2(C* val) { printf("%d\n", val->x); }
void f3(C& val) { printf("%d\n", val.x); }
C c(1); f1(c); f2(&c); f3(c);
All of the above functions pass their parameters by value (just as in D) but only the f1 has C as a parameter. f2 and f3 accept a pointer and a reference to C, respectively. So calling f1 will create a copy of C via C's copy ctor, while f2 and f3 will copy the address of C and end up referencing the original object. So executing the above should print:
0
1
1
Sean
|
September 23, 2006 Re: Overloading the assignment operator, right now! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | On Sat, 23 Sep 2006 01:03:25 +0300, Bruno Medeiros <brunodomedeiros+spam@com.gmail> wrote: > pragma wrote: >> Hasan Aljudy wrote: >>> >>> I vote: >>> No for copy operators. >>> Specially no for the ugly and cumbersome-to-type := operator. >>> >>> Yes for auto-generated copy methods/properties. (both deep and shallow) >>> >>> T x = b.dup.deep; >>> T y = b.dup.shallow; >> The only problem with this is that you can't have a compiler-generated deep copy without taking on some serious consequences and/or risks. IMO, that's too much effort for a compiler author, for a feature that is so limited in use and scope. >> > > I don't think you cave have a compiler-generated deep copy, *at all*. At least for the proper notion of "deep copy". > When one speaks of a clone method, or of a "deep copy", what one means (or at least *should* mean), is a copy of the "abstract state" of the object. A *conceptual* copy of the the object. [snip] I agree. The compiler cannot know the abstract states of objects. Human can make very good assumptions or guesses, but I think that one still have to look at the documentation to be 100% sure, in a general case at least. So, you have to implement clone methods by yourself, which can be a lot of work. I guess this is one of the reasons that objects in D are reference types. Of course, nothing prevents you to implement clone functions by yourself, but used in common 'calculations', it's cumbersome. Well, sometimes you could use structs instead of classes, but not always. One solution could indeed be a copy operator (which should be easy to type; suggestions?). The copy operator would simply call the clone method if it exists. But, copying value types around can be time consuming, though. For example, in C++: class HugeMatrix; HugeMatrix func() { HugeMatrix a, b, c, d; ... d = (a + b) - c; ... return d; } 'HugeMatrix' gets copied four times. Using references (as in D): HugeMatrix func() { HugeMatrix a, b, c; ... d = (a.clone().add(b)).sub(c); ... return d; } copying is done only once. It's efficient, but not pretty. Of course, one could use lazy copying in C++, but that cannot be automatically implemented by the compiler. (Well, I remember reading a paper where C++ templates were used in a bizarre way to get rid of creating unnecessary temporaries in such calculations... where I put it...) Could it be possible that the compiler would do the following conversion: "d = (a + b) - c;" -> "d = (a.opClone().opAdd(b)).opSub(c);" 'd' would be marked as 'copyable object' in the class declaration, or something, so that compiler will know that the 'opClone()' should be called in such situations. |
Copyright © 1999-2021 by the D Language Foundation