www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is operator overloading like this in D?

reply CloudiDust <zrc71105129 yahoo.com.cn> writes:
Greetings everybody, I am a novice in the D world (as well as one in a
newsgroup), come from the realm of C++. As I am so used to the operator
overloading mechanism in C++, it's strange enough for me that the D way
differs in a few aspects, as follows:

1. The cast operator can have only one overloaded version.

Is it a way to force the programmers not to rely on type cast?

2. There is nothing like "opPreInc".

In the reference, I got the point that "Since ++e is defined to be
semantically equivalent to (e += 1), the expression ++e is rewritten as (e +=
1) ...", so what if I only intend to overload the ++e, not the += operator,
just like the way STL defined its input / forward iterators?

3. On the missing of "opAssign".

Mr.Bright (I suppose :) stressed that we do not need to overload the
assignment operator to do anything other than a bit copy. So if one struct
contains pointers or references to others, we are hit. Maybe I am so immersed
in the C++ way that I feel the way like java / C# is slightly misleading.
Could you give me some advice on how to "overcome" that?

BTW: I wonder if the scoped objects are still references, as they are "newed"?

Many thanks for your time,
  ~CloudiDust
Dec 09 2006
parent reply Daniel Keep <daniel.keep+lists gmail.com> writes:
CloudiDust wrote:
 Greetings everybody, I am a novice in the D world (as well as one in a
 newsgroup), come from the realm of C++. As I am so used to the operator
 overloading mechanism in C++, it's strange enough for me that the D way
 differs in a few aspects, as follows:

Welcome :)
 1. The cast operator can have only one overloaded version.
 
 Is it a way to force the programmers not to rely on type cast?

Pretty much. For example, if you use cast(int)(some_float), then you have no control over what sort of cast: does it round (and if so, in what direction), or does it just truncate? The way to do this in D is to use a toType() function.
 2. There is nothing like "opPreInc".
 
 In the reference, I got the point that "Since ++e is defined to be
 semantically equivalent to (e += 1), the expression ++e is rewritten as (e +=
 1) ...", so what if I only intend to overload the ++e, not the += operator,
 just like the way STL defined its input / forward iterators?

I think this has been done to prevent people from playing semantic silly-buggers with operators, like how C++ overloaded "+" to mean "concatenation" with strings. This way, ++ always means "+= 1". You have a reasonable expectation that operators do what you would expect them to. At the very least, "ptr.next" is self-explanatory, whilst "++ptr" isn't as much :3
 3. On the missing of "opAssign".
 
 Mr.Bright (I suppose :) stressed that we do not need to overload the
 assignment operator to do anything other than a bit copy. So if one struct
 contains pointers or references to others, we are hit. Maybe I am so immersed
 in the C++ way that I feel the way like java / C# is slightly misleading.
 Could you give me some advice on how to "overcome" that?

Don't forget that because D is garbage collected, in the most cases, you don't need to do anything special if you have pointers. The GC will take care of things for you. If you really *do* need to copy the data a structure is pointing to, my suggestion would be to implement "dup" member functions. It's a little inconvenient, but it means that you can always count on "=" just doing a bit copy, and not something more. So "a = b" means "do a bit copy of b", and "a = b.dup" means "duplicate b in entirety". Plus, if you need to control how deep the copy does, you can use an argument.
 BTW: I wonder if the scoped objects are still references, as they are "newed"?

Not really sure. I'll have to disassemble some code to check... :)
 Many thanks for your time,
   ~CloudiDust

No problem, hope this helped and enjoy your stay. -- Daniel
Dec 09 2006
parent reply CloudiDust <zrc71105129 yahoo.com.cn> writes:
Thank you very much Daniel!

I wonder how to quote when posting?

You wrote: (I quoted it manually :)

 If you really *do* need to copy the data a structure is pointing to, my
 suggestion would be to implement "dup" member functions.  It's a little
 inconvenient, but it means that you can always count on "=" just doing a
 bit copy, and not something more.

It seems that dup is not a member of Object according to the library reference, why? Is it because not everything can be duplicated? On the other hand, as there are many classes with which less or greater than comparisons (even equality tests) makes no sense, why opCmp becomes a "default"? Resulting in a requirement to make arguments of opCmp be of type Object when overloading? ( Maybe I'm just feeling unused to test the type of objects inside the functions. :) If not overloaded, opEquals does a bit comparison on everything, doesn't it? And from the reference, I get: "If a struct has no opCmp() function declared for it, attempting to compare two structs is an error." And what does the default opCmp do with classes? ~CloudiDust
Dec 10 2006
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
CloudiDust wrote:
 On the other hand, as there are many classes with which less or greater than
 comparisons (even equality tests) makes no sense, why opCmp becomes a
"default"?
 Resulting in a requirement to make arguments of opCmp be of type Object when
 overloading?

That's to allow calling it if you only have an Object reference. This is used in the implementation of associative arrays, and maybe some other places in the standard library.
 ( Maybe I'm just feeling unused to test the type of objects inside the
functions. :)
 
 If not overloaded, opEquals does a bit comparison on everything, doesn't it?

In structs, yes. In classes, Object.opEquals compares addresses (object identity).
 And from the reference, I get: "If a struct has no opCmp() function declared
for
 it, attempting to compare two structs is an error."
 
 And what does the default opCmp do with classes?

Throw an exception. (It used to compare addresses, but that was bad because then the result can change between GC cycles if a moving collector is implemented)
Dec 10 2006
prev sibling parent reply Daniel Keep <daniel.keep+lists gmail.com> writes:
CloudiDust wrote:
 Thank you very much Daniel!
 
 I wonder how to quote when posting?

I use a real news client, so I hit the "Reply" button :3
 You wrote: (I quoted it manually :)
 
 
If you really *do* need to copy the data a structure is pointing to, my
suggestion would be to implement "dup" member functions.  It's a little
inconvenient, but it means that you can always count on "=" just doing a
bit copy, and not something more.

It seems that dup is not a member of Object according to the library reference, why? Is it because not everything can be duplicated?

Because it's not part of the library. "dup" is a property of arrays, and sort of got extended to other things. You could name the method "copy" or "duplicate" or "frobnicate"--it's just a name, afterall. As long as you use it consistantly, it shouldn't be a problem.
 On the other hand, as there are many classes with which less or greater than
 comparisons (even equality tests) makes no sense, why opCmp becomes a
"default"?
 Resulting in a requirement to make arguments of opCmp be of type Object when
 overloading?
 
 ( Maybe I'm just feeling unused to test the type of objects inside the
functions. :)
 
 If not overloaded, opEquals does a bit comparison on everything, doesn't it?
 
 And from the reference, I get: "If a struct has no opCmp() function declared
for
 it, attempting to compare two structs is an error."
 
 And what does the default opCmp do with classes?

I'll leave that to Frits, who has already answered it :)
  ~CloudiDust

Dec 11 2006
parent CloudiDust <zrc71105129 yahoo.com.cn> writes:
Thank you both Daniel & Frits.

So it means generally we should be careful using operator overloading and prefer
"named" functions. :)
Dec 13 2006