Thread overview
Why is operator overloading like this in D?
Dec 10, 2006
CloudiDust
Dec 10, 2006
Daniel Keep
Dec 10, 2006
CloudiDust
Dec 10, 2006
Frits van Bommel
Dec 12, 2006
Daniel Keep
Dec 13, 2006
CloudiDust
December 10, 2006
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
December 10, 2006
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
December 10, 2006
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
December 10, 2006
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)
December 12, 2006
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
December 13, 2006
Thank you both Daniel & Frits.

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