www.digitalmars.com         C & C++   DMDScript  

D - [BUG?]: operator overloading

reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
I asked this question before but here it is again:
For example i have this code

class A
{
 A opShl(int x)
 {
  printf("%d",x);
  return this;
 }
 A opShl(char[] x)
 {
  printf("%.*s",x);
  return this;
 }
}

class B
{
 A opShl_r(A a)
 {
  //some code..
  return a;
 }
}

int main(char[][] args)
{
 A a;
 a << 4 << " " << 12 << "\n";
 B b = new B();

 a << b;
 getch();
 return 1;
}

The line a<<b; causes this compilation error:
E:\D language\learn_d\cout\cout.d(36): function opShl (int x) does not match
argument types (B )

The compiler look for A.opShl(B) but it doesnt seam to look for
B.opShl_r(A)??
If A.opShl(*) functions don't exist then the compiler finds and calls
B.opShl_e(A),
but then the first line
 a << 4 << " " << 12 << "\n";
doesn't work!

So is this a bug?
I hope it is and that it gets fixed!
Mar 22 2004
next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Ivan Senji wrote:

[...]
 The compiler look for A.opShl(B) but it doesnt seam to look for
 B.opShl_r(A)??

From the spec: | a op b [...] | If a is a struct or class object reference that contains a member named | opfunc, the expression is rewritten as: | a.opfunc(b) Because your A contains `opShl' this rule holds and your B is not searched for `opShl_r'. According to the current specification it is not a bug to consider your code as erroneous. However, I consider the specification as either buggy itself, because it only defines a precendece, wheras it should disallow operands competing for operators at all, or the specification should be extended, so that only operands competing for operators using corresponding signature pairs are disallowed. Thoughts?
Mar 23 2004
next sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:c3rdt2$1d7g$1 digitaldaemon.com...
 Ivan Senji wrote:

 [...]
 The compiler look for A.opShl(B) but it doesnt seam to look for
 B.opShl_r(A)??

From the spec: | a op b [...] | If a is a struct or class object reference that contains a member named | opfunc, the expression is rewritten as: | a.opfunc(b) Because your A contains `opShl' this rule holds and your B is not searched for `opShl_r'.

I dont't agree! A contains functions opShl(int) and opShl(char[]) but it doesnt contain opShl(B) so it should still check if B contains opShl(A).
 According to the current specification it is not a bug to consider your
 code as erroneous.

 However, I consider the specification as either buggy itself, because it
 only defines a precendece, wheras it should disallow operands competing
 for operators at all, or the specification should be extended, so that
 only operands competing for operators using corresponding signature pairs
 are disallowed.

 Thoughts?

Mar 24 2004
parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Ivan Senji schrieb:

 I dont't agree! A contains functions opShl(int) and opShl(char[]) but it
 doesnt contain
 opShl(B) so it should still check if B contains opShl(A).

I don't "agree" either, but so is the current spec. I checked it. -eye
Mar 24 2004
parent reply Juan c <Juan_member pathlink.com> writes:
Huh?! But A<<B is not the same as B<<A. I think you are trying to abuse the
operator, and Walter doesn't like that. The << operator should _only_ be used to
perform a left-shifting operation, which is not commutative.


In article <c3sbqj$2s6n$2 digitaldaemon.com>, Ilya Minkov says...
Ivan Senji schrieb:

 I dont't agree! A contains functions opShl(int) and opShl(char[]) but it
 doesnt contain
 opShl(B) so it should still check if B contains opShl(A).

I don't "agree" either, but so is the current spec. I checked it. -eye

Mar 24 2004
next sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Juan c" <Juan_member pathlink.com> wrote in message
news:c3sf1l$ib$1 digitaldaemon.com...
 Huh?! But A<<B is not the same as B<<A. I think you are trying to abuse

 operator, and Walter doesn't like that. The << operator should _only_ be

 perform a left-shifting operation, which is not commutative.

A.opShl(B) should be same as B.opShl_r(A). I don't think it is abusing the operator if I am trying to use it to write simpler code! I (and probably a lot of other people coming from C++) see << and >> as stream operators before left-shifting. Someone may overload a static opCall operator to be able to use it like this A a = A(3,5); instead of A a = new A(3,5); Is this also abuse? I see it as a freedom to express your ideas in different ways.
 In article <c3sbqj$2s6n$2 digitaldaemon.com>, Ilya Minkov says...
Ivan Senji schrieb:

 I dont't agree! A contains functions opShl(int) and opShl(char[]) but



 doesnt contain
 opShl(B) so it should still check if B contains opShl(A).

I don't "agree" either, but so is the current spec. I checked it. -eye


Mar 24 2004
next sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Ivan Senji wrote:

[...]
 A.opShl(B) should be same as B.opShl_r(A).

Should be. But this cannot be checked in the general case. Therefore the coexistence of both must be forbidden. I am unsure whether the compiler should check that for all possible competing classes/structs or it may suffice to check it only, when such classes/structs actually compete. [...]
 see << and >> as stream operators

Which is a strange and counter intuitive speciality made for {101}'s, not suitable for {500}'s. So long!
Mar 24 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:c3sl87$c96$2 digitaldaemon.com...
 Ivan Senji wrote:

 [...]
 A.opShl(B) should be same as B.opShl_r(A).

Should be. But this cannot be checked in the general case. Therefore the coexistence of both must be forbidden.

My example doesn't involve coexistence of both operators! I I only have B.opShl_r(A) and it is not called because A.opShl(int) and A.opShl(char[]) exist.
 I am unsure whether the compiler should check that for all possible
 competing classes/structs or it may suffice to check it only, when such
 classes/structs actually compete.

 [...]
 see << and >> as stream operators

Which is a strange and counter intuitive speciality made for {101}'s, not suitable for {500}'s. So long!

Mar 24 2004
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Ivan Senji wrote:

[...]
 My example doesn't involve coexistence of both operators! I
 I only have B.opShl_r(A) and it is not called because A.opShl(int) and
 A.opShl(char[]) exist.

I noticed that. And because your classes do not compete for the `<<' operator, there is good reason to allow B's `opShl_r' to be called. There is one more reason that especially your example should be allowed: your `opShl_r' returns the type of the left operand, which is the only requirement for the `<<' operator, which can be extracted from the spec. And as far as I can deduce from opover.c this requirement is not checked for by dmd. However, are you aware that your approach to mimic C++'s stream operator in D is illegal according to the spec? That is because the evaluation order for the operands of consecutive `<<'s is not defined. In the current version of dmd it may work, but in the next version or in another compiler may result in a syntax error. If you want such evaluated from left to right, you have to put it fully in brackets from left to right, which would totally obfuscate your purpose. So long!
Mar 24 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:c3sqjj$tq9$1 digitaldaemon.com...
 Ivan Senji wrote:

 [...]
 My example doesn't involve coexistence of both operators! I
 I only have B.opShl_r(A) and it is not called because A.opShl(int) and
 A.opShl(char[]) exist.

I noticed that. And because your classes do not compete for the `<<' operator, there is good reason to allow B's `opShl_r' to be called. There is one more reason that especially your example should be allowed: your `opShl_r' returns the type of the left operand, which is the only requirement for the `<<' operator, which can be extracted from the spec. And as far as I can deduce from opover.c this requirement is not checked for by dmd. However, are you aware that your approach to mimic C++'s stream operator in D is illegal according to the spec? That is because the evaluation order for the operands of consecutive `<<'s is not defined. In the current version of dmd it may work, but in the next version or in another compiler may result in a syntax error.

OOPS! I didn't realize that(Thanks). But it isn't my intention to mimic C++'s streams, i am only experimenting :) I have another example (for this one no one can say it is abuse of operators): Lets say someone wrote a library that has a Matrix class. And I write a Vector class because i need it and i would like to use it together with Matrix Matrix class has "Matrix.opMul(Matrix)" and i wan't my Vector class to have Vector opMul(Matrix m) now i can use it like this: Matrix m1 = v1 * m2; but i can't use it like this: Matrix m1 = m2 * v1; Even if there existed opMul_r operator (i don't know why there isn't one) this still wouldn't work becouse of the Matrix.opMul(Matrix)! I like most every other feature of D very much (especially templates) but i just think there is something wrong in D's operator overloading! I don't think there is any solution to the problems like the one with Matrix and Vector. :( ?
 If you want such evaluated from left to right, you have to put it fully in
 brackets from left to right, which would totally obfuscate your purpose.

 So long!

Mar 24 2004
parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Ivan Senji wrote:

"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:c3sqjj$tq9$1 digitaldaemon.com...
  

Ivan Senji wrote:

[...]
    

My example doesn't involve coexistence of both operators! I
I only have B.opShl_r(A) and it is not called because A.opShl(int) and
A.opShl(char[]) exist.
      

I noticed that. And because your classes do not compete for the `<<' operator, there is good reason to allow B's `opShl_r' to be called. There is one more reason that especially your example should be allowed: your `opShl_r' returns the type of the left operand, which is the only requirement for the `<<' operator, which can be extracted from the spec. And as far as I can deduce from opover.c this requirement is not checked for by dmd. However, are you aware that your approach to mimic C++'s stream operator in D is illegal according to the spec? That is because the evaluation order for the operands of consecutive `<<'s is not defined. In the current version of dmd it may work, but in the next version or in another compiler may result in a syntax error.

OOPS! I didn't realize that(Thanks). But it isn't my intention to mimic C++'s streams, i am only experimenting :) I have another example (for this one no one can say it is abuse of operators): Lets say someone wrote a library that has a Matrix class. And I write a Vector class because i need it and i would like to use it together with Matrix Matrix class has "Matrix.opMul(Matrix)" and i wan't my Vector class to have Vector opMul(Matrix m) now i can use it like this: Matrix m1 = v1 * m2; but i can't use it like this: Matrix m1 = m2 * v1; Even if there existed opMul_r operator (i don't know why there isn't one) this still wouldn't work becouse of the Matrix.opMul(Matrix)!

the same thing. Check out dig for a good matrix class. -- -Anderson: http://badmama.com.au/~anderson/
Mar 24 2004
parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3t0ha$17ta$1 digitaldaemon.com...

 In this case the operation is comunitative, so m2 * v1 and v1 * m2 are
 the same thing.  Check out dig for a good matrix class.

Ok but what if i for some reason neaded two vecto classes vectorRow and vectorColumn (and nobody can say that noone will ever need something like this) wtih these two vector classes m2*v1and v1*m2 isn't comutative. It isn't the same result if yout multiply a matrix with a vector row from left or from the right side.
Mar 25 2004
parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Ivan Senji wrote:

"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3t0ha$17ta$1 digitaldaemon.com...

  

In this case the operation is comunitative, so m2 * v1 and v1 * m2 are
the same thing.  Check out dig for a good matrix class.

    

Ok but what if i for some reason neaded two vecto classes vectorRow and vectorColumn (and nobody can say that noone will ever need something like this) wtih these two vector classes m2*v1and v1*m2 isn't comutative. It isn't the same result if yout multiply a matrix with a vector row from left or from the right side.

but if it's possible then it is not much trouble. -- -Anderson: http://badmama.com.au/~anderson/
Mar 25 2004
next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3ueha$e35$1 digitaldaemon.com...

but if it's possible then it is not much trouble.

It is mathematicaly possible to do m2 * v1, but it isn't D-possible when the left side class (int this case matrix) has a * operator defined.
Mar 25 2004
prev sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3ueha$e35$1 digitaldaemon.com...
 Your right I was thinking scalar. Anyway  you shouldn't be able m2 x v1
 but if it's possible then it is not much trouble.

It is amthematicaly possible to do that, but it isn't D-possible when the left side class (in this case matrix) has any opMul defined! This is the problem: If class matrix doesn't have any operators opMul then vector is searched for opMul_r(matrix), but in the case of existance of matrix.opMul it doen't work.
Mar 25 2004
parent J Anderson <REMOVEanderson badmama.com.au> writes:
Ivan Senji wrote:

"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c3ueha$e35$1 digitaldaemon.com...
  

Your right I was thinking scalar. Anyway  you shouldn't be able m2 x v1
but if it's possible then it is not much trouble.
    

It is amthematicaly possible to do that, but it isn't D-possible when the left side class (in this case matrix) has any opMul defined! This is the problem: If class matrix doesn't have any operators opMul then vector is searched for opMul_r(matrix), but in the case of existance of matrix.opMul it doen't work.

for m x v and a column for v x m. -- -Anderson: http://badmama.com.au/~anderson/
Mar 25 2004
prev sibling parent reply Juan C <Juan_member pathlink.com> writes:
<snip>
I (and probably a lot of other people coming from C++) see <<
and >> as stream operators before left-shifting.

And it seems that's _why_ Walter doesn't want operators to be (ab)used for things like that. << is leftshift, >> is rightshift, and should _never_ have been used as stream operators in the first place. And even as stream operators; A<<B is not the same as B<<A !!
Mar 24 2004
parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Juan C schrieb:

 And it seems that's _why_ Walter doesn't want operators to be (ab)used for
 things like that. << is leftshift, >> is rightshift, and should _never_ have
 been used as stream operators in the first place.

Perhaps. This is not the subject now.
 And even as stream operators; A<<B is not the same as B<<A !!

Like, you're not getting it. We are only talking of A<<B - but insert something more sane in the place of <<, it can be % or ~ or whatever. This case can be resolved as A.Op(B) or B.Op_r(A). Notice that _r? It's to be able to expand the operator overloads without changing established class libraries. Now, the compiler refuses to consider the B.Op_r(A) resolution, because A.Op() is defined for some other type than B. This nonsensical situatition conforms to the specification. So i'd say the spec should be changed. It's not simply nonsensical, it's outright dangerous. Imagine A doesn't define .Op and there is a ton arbitrary code which defines .Op_r(A). Then the author of A decides to add a few .Op overloads to it. This breaks all other code which relies on the definitions of .Op_r(A), even if there is *no* *direct* *conflict*, that is no definition of C.Op_r(A) corresponds to A.Op(C) simply because the author of A is not aware of C, but C is aware of and requieres/uses A. -eye
Mar 24 2004
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Ilya Minkov wrote:

[...]
 Imagine A doesn't define .Op and there is a ton arbitrary 
 code which defines .Op_r(A). Then the author of A decides to add a few 
 .Op overloads to it. This breaks all other code which relies on the 
 definitions of .Op_r(A), even if there is *no* *direct* *conflict*, that 
 is no definition of C.Op_r(A) corresponds to A.Op(C) simply because the 
 author of A is not aware of C, but C is aware of and requieres/uses A.

I think that this is the pioneering argument, provided that it is posssible to code .Op_r by having access only to the public parts of A. Now to the next steps: 1) should the compiler check for competing overloads that may coincide, but actualyy do not; or should this checking only be done, when an overload is actually established; or should this being laid into the hands of the implementor of the compiler. 2) especially in the not overloaded case of `<<' it is defined, that the type of the result must be the type of the left operand. Should the compiler check the overloading functions for this requirement? Note: I think the latter has to do with the term `abuse', that sometimes drop into the discussions here. This reminds me of the french quotation marks "<<" and ">>". Would it be abuse, if someone would overload the shift operators in such a way, that they can be used as quotation marks? Moreover, in france quotations are made like "<< quoted text >>", whereas in germany the quotations are made ">> quoted text <<", if this quotation marks are used at all. So long!
Mar 25 2004
parent Ilya Minkov <minkov cs.tum.edu> writes:
Manfred Nowak schrieb:

 Ilya Minkov wrote:
 
 [...]
 
Imagine A doesn't define .Op and there is a ton arbitrary 
code which defines .Op_r(A). Then the author of A decides to add a few 
.Op overloads to it. This breaks all other code which relies on the 
definitions of .Op_r(A), even if there is *no* *direct* *conflict*, that 
is no definition of C.Op_r(A) corresponds to A.Op(C) simply because the 
author of A is not aware of C, but C is aware of and requieres/uses A.

I think that this is the pioneering argument, provided that it is posssible to code .Op_r by having access only to the public parts of A. Now to the next steps: 1) should the compiler check for competing overloads that may coincide, but actualyy do not; or should this checking only be done, when an overload is actually established; or should this being laid into the hands of the implementor of the compiler.

We can solve it like many similar questions. It is an error to define ambiguous overloads. It is a quality of implementation issue, if and under what circumstances the compiler can actually detect such an error. I would think that a simple compiler may provide the direct .op overload a precedence, while an advanced compiler may, when compiling a class which contains B.op_r(A), check that there is no match for A.op(B) and indicate an error if there is, and vice versa. I think i have to think over it a bit, since D allows covariant arguments, as opposed to C++ where they are invariant.
 2) especially in the not overloaded case of `<<' it is defined, that the
 type of the result must be the type of the left operand. Should the
 compiler check the overloading functions for this requirement?

Hard to tell. I think rather not, as it currently is.
 Note: I think the latter has to do with the term `abuse', that sometimes
 drop into the discussions here. This reminds me of the french quotation
 marks "<<" and ">>". Would it be abuse, if someone would overload the
 shift operators in such a way, that they can be used as quotation marks?
 Moreover, in france quotations are made like "<< quoted text >>", whereas
 in germany the quotations are made ">> quoted text <<", if this quotation
 marks are used at all.

Not much i could say here. Numeric operators were foreseen for numeric stuff, other operators were foreseen for their corresponding meanings. And while sprinkled abuse in general code may be very misleading, there is e.g. a C++ library which defines parsers in an elegant manner by using up an operator abuse. The way it is done there, the abuse is obvious and thus doesn't lead to problems. -eye
Mar 25 2004
prev sibling next sibling parent Carlos Santander B. <Carlos_member pathlink.com> writes:
In article <c3sf1l$ib$1 digitaldaemon.com>, Juan c says...
Huh?! But A<<B is not the same as B<<A. I think you are trying to abuse the
operator, and Walter doesn't like that. The << operator should _only_ be used to
perform a left-shifting operation, which is not commutative.

But he isn't doing that. He defined A.opShl(int) so he can do A<<3. He also wants to do A<<B, so he defined B.opShl_r(A), which should work, but doesn't. Yes, maybe he is abusing the operator, but that's his problem. Or maybe not: what if B is BigInteger? Then he wouldn't be abusing. One way or another, he's in all his rights to do things like this. ------------------- Carlos Santander B.
Mar 24 2004
prev sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Juan c" <Juan_member pathlink.com> wrote in message
news:c3sf1l$ib$1 digitaldaemon.com...
 Huh?! But A<<B is not the same as B<<A. I think you are trying to abuse

 operator, and Walter doesn't like that. The << operator should _only_ be

 perform a left-shifting operation, which is not commutative.

I was wondering... what is the definition of abuse of operator? This code can be written in D, is this abuse? class ABC { static int opMul(char[] x){return 1;} static ABC opDiv(char[] x){return new ABC();} } ABC * "hello"; ABC abc = ABC / "hello again"; Is this code abuse? I think that there can't even be a definition of operator abuse because todays language features allow us to write things like the above. In the code above * and / obviously dont have the meaning of multiplication and division, but i like that we have the freedom to write something like that. Maybe the above code could have meaning to someone in some situation. It doesn't make sence that the language lets us write things like the above, but makes it impossible to use operators in some very common situations!
 In article <c3sbqj$2s6n$2 digitaldaemon.com>, Ilya Minkov says...
Ivan Senji schrieb:

 I dont't agree! A contains functions opShl(int) and opShl(char[]) but



 doesnt contain
 opShl(B) so it should still check if B contains opShl(A).

I don't "agree" either, but so is the current spec. I checked it. -eye


Mar 24 2004
parent reply Juan C <Juan_member pathlink.com> writes:
<snip>
I was wondering... what is the definition of abuse of operator?

It can't be defined, because not everyone would agree with any particular definition, or even whether or not such a concept is valid. I could say, "any implementation of an operator that differs substantially from its normal mathematical meaning". But that can be viewed as vague and maybe only half the people in this group would agree that that's abuse anyway. Many, like you perhaps, would argue that any operator can be used for any purpose. <analogy> Even though my SUV _allows_ me to drive anywhere, I am still obliged to follow the roads, so that other drivers can _reasonably predict_ what I'm likely to do. </analogy>
Mar 24 2004
parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Juan C" <Juan_member pathlink.com> wrote in message
news:c3t04c$17d8$1 digitaldaemon.com...
 <snip>
I was wondering... what is the definition of abuse of operator?

It can't be defined, because not everyone would agree with any particular definition, or even whether or not such a concept is valid. I could say, "any implementation of an operator that differs substantially

 its normal mathematical meaning". But that can be viewed as vague and

 half the people in this group would agree that that's abuse anyway. Many,

 you perhaps, would argue that any operator can be used for any purpose.

 <analogy>
 Even though my SUV _allows_ me to drive anywhere, I am still obliged to

 the roads, so that other drivers can _reasonably predict_ what I'm likely

 </analogy>

Your car allows you to drive anywhere but the comunity doesn't, you can be punished. Same with the operators.If i write a library and the users think i am abusing operators nobody will use the library, and this will be my punishment! But we live in a free world so it shouldn't be made impossible to write inovative code wich in some context maybe makes sence.
Mar 25 2004
prev sibling parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Manfred Nowak schrieb:
 However, I consider the specification as either buggy itself, because it
 only defines a precendece, wheras it should disallow operands competing
 for operators at all, or the specification should be extended, so that
 only operands competing for operators using corresponding signature pairs
 are disallowed.

So it is. The purpose of _r overloads was to be able to add new overloads in newly written classes to the already exisiting infrastructure. With a current limitation, it does not fulfill this purpose. Consider that, e.g. class A is in the library, and B is user-written. A defines some operators for built-in and library types. Now this operator also should be made work with user types. The only sensible way to accomplish this is that if an overload search in A failed (that is, there possibly is an operator overload, but it doesn't match) a reversed overload has to be searched in B. Walter: was it a conscious decision to disallow that _r overloads be ignored in B if A defines some direct overload of this operator? The way it is now it's utterly useless and you could just as well remove all _r overloads! -eye
Mar 24 2004
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Ilya Minkov wrote:

[...]
 The purpose of _r overloads was to be able to add new 
 overloads in newly written classes to the already exisiting 
 infrastructure.

Do you have a reference for this? I ask, because I do not believe, that classes in any infrastructure are not allowed to have other types than classes/structs on the left side of a non commutative operator. [...]
 but it doesn't match) a reversed overload has to be searched in B.

I do not believe that it is possible to code such overloads in the general case you established as an example. How can you assure, that it would suffice to have access to the public parts of class/struct A? [...]
 you could just as well remove all _r overloads!

A stated above `B.opfunc_r(int)' may still make sense. So long!
Mar 24 2004
next sibling parent reply "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Manfred Nowak" <svv1999 hotmail.com> wrote in message
news:c3sl7u$bjt$1 digitaldaemon.com...
 Ilya Minkov wrote:

 [...]
 The purpose of _r overloads was to be able to add new
 overloads in newly written classes to the already exisiting
 infrastructure.

Do you have a reference for this? I ask, because I do not believe, that classes in any infrastructure are not allowed to have other types than classes/structs on the left side of a non commutative operator.

Not true, example from spec: class B { int opDiv_r(int i); } B b; 1 / b; // equivalent to b.opDiv_r(1)
 [...]
 but it doesn't match) a reversed overload has to be searched in B.

I do not believe that it is possible to code such overloads in the general case you established as an example. How can you assure, that it would suffice to have access to the public parts of class/struct A? [...]
 you could just as well remove all _r overloads!

A stated above `B.opfunc_r(int)' may still make sense. So long!

Mar 24 2004
parent Manfred Nowak <svv1999 hotmail.com> writes:
Ivan Senji wrote:

[...]
 Not true, example from spec:
 
 class B { int opDiv_r(int i); }
 	B b;
 	1 / b;	// equivalent to b.opDiv_r(1)

Thanks for this confirmation from the spec for my suspicion. So long!
Mar 24 2004
prev sibling parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Manfred Nowak schrieb:

 Ilya Minkov wrote:
 
 [...]
 
The purpose of _r overloads was to be able to add new 
overloads in newly written classes to the already exisiting 
infrastructure.

[...] Do you have a reference for this? I ask, because I do not believe, that classes in any infrastructure are not allowed to have other types than classes/structs on the left side of a non commutative operator.

Ok, you're right. But here's a real-life example: A widespread library defines numerical class A. For it, operators to divide it by an integer a float, and so on. are defined. Then you go ahead and write a Fixpoint struct. You want that you can divide A by your fixpoint just as by integer or a float. And you don't want to change A because you don't own it, and because you don't want A to be dependant on your fixpoint. So you define Fixpoint.opDiv_r(A). But hey, in current spec it DOES NOT WORK because A.opDiv(int) or some other unrelated stuff is defined!!! Now, one could consider not to define opDiv in A at all. But in the examples like above it simply doesn't come into consideration, because there is no other way to make it work with D's built in types!!! This is hardly acceptable. And while there is a workaround for classes by using interfaces, for structs it is a real dead end.
 [...]
 
but it doesn't match) a reversed overload has to be searched in B.

I do not believe that it is possible to code such overloads in the general case you established as an example. How can you assure, that it would suffice to have access to the public parts of class/struct A?

I cannot, but imagine you are writing a library. You want that people can write extensions to your library. So you make sure they can - by making something public, or by providing a constructor. Of course it is only for cases which are foreseen. In principle, this situation is analogous to that of freestanding operators in C++, just that we don't have "friend", which wouldn't help here either.
you could just as well remove all _r overloads!

A stated above `B.opfunc_r(int)' may still make sense.

Ok. i exaggerated. But the usefulness diminishes to almost zero. There was a discussion on freestanding operators. Everyone wanted them. Just that they don't live well with D's module system. Walter was strongly against. I had suggested that what they requiere, namely extensibility, can be achieved also with reverse overloads. Now i see that this doesn't work in the current spec. So, the discussion must be unrolled again, either freestanding operators, or reverse overloads which don't fail when non-conflicting direct overloads are defined. -eye
Mar 24 2004
parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:c3t1i5$19pm$1 digitaldaemon.com...
 Manfred Nowak schrieb:

 Ilya Minkov wrote:

 [...]

The purpose of _r overloads was to be able to add new
overloads in newly written classes to the already exisiting
infrastructure.

[...] Do you have a reference for this? I ask, because I do not believe, that classes in any infrastructure are not allowed to have other types than classes/structs on the left side of a non commutative operator.

Ok, you're right. But here's a real-life example: A widespread library defines numerical class A. For it, operators to divide it by an integer a float, and so on. are defined. Then you go ahead and write a Fixpoint struct. You want that you can divide A by your fixpoint just as by integer or a float. And you don't want to change A because you don't own it, and because you don't want A to be dependant on your fixpoint. So you define Fixpoint.opDiv_r(A). But hey, in current spec it DOES NOT WORK because A.opDiv(int) or some other unrelated stuff is defined!!! Now, one could consider not to define opDiv in A at all. But in the examples like above it simply doesn't come into consideration, because there is no other way to make it work with D's built in types!!! This is hardly acceptable. And while there is a workaround for classes by using interfaces, for structs it is a real dead end.
 [...]

but it doesn't match) a reversed overload has to be searched in B.

I do not believe that it is possible to code such overloads in the


 case you established as an example. How can you assure, that it would
 suffice to have access to the public parts of class/struct A?

I cannot, but imagine you are writing a library. You want that people can write extensions to your library. So you make sure they can - by making something public, or by providing a constructor. Of course it is only for cases which are foreseen. In principle, this situation is analogous to that of freestanding operators in C++, just that we don't have "friend", which wouldn't help here either.
you could just as well remove all _r overloads!

A stated above `B.opfunc_r(int)' may still make sense.

Ok. i exaggerated. But the usefulness diminishes to almost zero. There was a discussion on freestanding operators. Everyone wanted them. Just that they don't live well with D's module system. Walter was strongly against. I had suggested that what they requiere, namely extensibility, can be achieved also with reverse overloads. Now i see that this doesn't work in the current spec. So, the discussion must be unrolled again, either freestanding operators, or reverse overloads which don't fail when non-conflicting direct overloads are defined. -eye

All I can say is: Agree complety!
Mar 24 2004
prev sibling next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
Conclusion?: The way that operators work now should be changed because it is
dangerous.
The D way is generaly a good solution but they still have a big problem with
*_r operators!

"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:c3mdn2$225h$1 digitaldaemon.com...
 I asked this question before but here it is again:
 For example i have this code

 class A
 {
  A opShl(int x)
  {
   printf("%d",x);
   return this;
  }
  A opShl(char[] x)
  {
   printf("%.*s",x);
   return this;
  }
 }

 class B
 {
  A opShl_r(A a)
  {
   //some code..
   return a;
  }
 }

 int main(char[][] args)
 {
  A a;
  a << 4 << " " << 12 << "\n";
  B b = new B();

  a << b;
  getch();
  return 1;
 }

 The line a<<b; causes this compilation error:
 E:\D language\learn_d\cout\cout.d(36): function opShl (int x) does not

 argument types (B )

 The compiler look for A.opShl(B) but it doesnt seam to look for
 B.opShl_r(A)??
 If A.opShl(*) functions don't exist then the compiler finds and calls
 B.opShl_e(A),
 but then the first line
  a << 4 << " " << 12 << "\n";
 doesn't work!

 So is this a bug?
 I hope it is and that it gets fixed!

Mar 25 2004
prev sibling next sibling parent reply "Kris" <someidiot earthlink.net> writes:
There's an inter-related issue that exhibits this "short circuit" behavior:
*any* set of methods with the same basic name (foo, get, put, opShl ...) do
the same thing. For example, if I have two classes:

class A
{
    void foo(int x){}
    void foo(char[] x){}
    void foo(real x){}
}

class B : A
{
  void foo (ubyte x){}
}

void test()
{
   B b = new B();

   b.foo ("test");
}

The b.foo("test") generates a similar compile error ("function foo (ubyte x)
does not match argument types (char[4])"). Apparently, once the basic name
is found within a given class, the method resolver stops looking further
down the inheritance chain for a better match. I don't like this, but it's
per design (C++ does the same?).

Walter has a way around this particular issue using alias: there's an
additional small section in the online manual discussing it's use. However,
it's not fully supported in  release 0.81, and I don't know if it would
resolve Ivan's opShl_r problem. I got around the same _r issue (for DSC) by
applying an interface instead.

- Kris


"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:c3mdn2$225h$1 digitaldaemon.com...
 I asked this question before but here it is again:
 For example i have this code

 class A
 {
  A opShl(int x)
  {
   printf("%d",x);
   return this;
  }
  A opShl(char[] x)
  {
   printf("%.*s",x);
   return this;
  }
 }

 class B
 {
  A opShl_r(A a)
  {
   //some code..
   return a;
  }
 }

 int main(char[][] args)
 {
  A a;
  a << 4 << " " << 12 << "\n";
  B b = new B();

  a << b;
  getch();
  return 1;
 }

 The line a<<b; causes this compilation error:
 E:\D language\learn_d\cout\cout.d(36): function opShl (int x) does not

 argument types (B )

 The compiler look for A.opShl(B) but it doesnt seam to look for
 B.opShl_r(A)??
 If A.opShl(*) functions don't exist then the compiler finds and calls
 B.opShl_e(A),
 but then the first line
  a << 4 << " " << 12 << "\n";
 doesn't work!

 So is this a bug?
 I hope it is and that it gets fixed!

Mar 25 2004
parent reply Ilya Minkov <minkov cs.tum.edu> writes:
Kris schrieb:

 There's an inter-related issue that exhibits this "short circuit" behavior:
 *any* set of methods with the same basic name (foo, get, put, opShl ...) do
 the same thing. For example, if I have two classes:

--- 8< --- >8 ---
 The b.foo("test") generates a similar compile error ("function foo (ubyte x)
 does not match argument types (char[4])"). Apparently, once the basic name
 is found within a given class, the method resolver stops looking further
 down the inheritance chain for a better match. I don't like this, but it's
 per design (C++ does the same?).

Yes, it is by design and C++ does the same IIRC. I think there was some smart reason to it. You have to import all other defs using alias.
 Walter has a way around this particular issue using alias: there's an
 additional small section in the online manual discussing it's use. However,
 it's not fully supported in  release 0.81, and I don't know if it would
 resolve Ivan's opShl_r problem.

No, it won't. Incompatible types. And this issue is no way related. Both behaviours are parts of specification.
 I got around the same _r issue (for DSC) by
 applying an interface instead.

A pity it doesn't help for structs. If we had boxing it would, but then we would loose a lot of performance. -eye
Mar 25 2004
next sibling parent "Kris" <someidiot earthlink.net> writes:
My mistake ... <g>

"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:c3vf6p$242t$1 digitaldaemon.com...
 No, it won't. Incompatible types. And this issue is no way related. Both
 behaviours are parts of specification.

Mar 25 2004
prev sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Ilya Minkov" <minkov cs.tum.edu> wrote in message
news:c3vf6p$242t$1 digitaldaemon.com
| Kris schrieb:
|
|| There's an inter-related issue that exhibits this "short circuit"
behavior:
|| *any* set of methods with the same basic name (foo, get, put, opShl ...)
do
|| the same thing. For example, if I have two classes:
|
| --- 8< --- >8 ---
|
|| The b.foo("test") generates a similar compile error ("function foo (ubyte
x)
|| does not match argument types (char[4])"). Apparently, once the basic
name
|| is found within a given class, the method resolver stops looking further
|| down the inheritance chain for a better match. I don't like this, but
it's
|| per design (C++ does the same?).
|
| Yes, it is by design and C++ does the same IIRC. I think there was some
| smart reason to it. You have to import all other defs using alias.
|

However, the same can't be done for constructors.

-----------------------
Carlos Santander Bernal
Mar 25 2004
parent Ilya Minkov <minkov cs.tum.edu> writes:
Carlos Santander B. schrieb:

 However, the same can't be done for constructors.

They should call superclass constructors. -eye
Mar 26 2004
prev sibling parent "Walter" <newshound digitalmars.com> writes:
You're right, it should work, and it does now. -Walter

"Ivan Senji" <ivan.senji public.srce.hr> wrote in message
news:c3mdn2$225h$1 digitaldaemon.com...
 I asked this question before but here it is again:
 For example i have this code

 class A
 {
  A opShl(int x)
  {
   printf("%d",x);
   return this;
  }
  A opShl(char[] x)
  {
   printf("%.*s",x);
   return this;
  }
 }

 class B
 {
  A opShl_r(A a)
  {
   //some code..
   return a;
  }
 }

 int main(char[][] args)
 {
  A a;
  a << 4 << " " << 12 << "\n";
  B b = new B();

  a << b;
  getch();
  return 1;
 }

 The line a<<b; causes this compilation error:
 E:\D language\learn_d\cout\cout.d(36): function opShl (int x) does not

 argument types (B )

 The compiler look for A.opShl(B) but it doesnt seam to look for
 B.opShl_r(A)??
 If A.opShl(*) functions don't exist then the compiler finds and calls
 B.opShl_e(A),
 but then the first line
  a << 4 << " " << 12 << "\n";
 doesn't work!

 So is this a bug?
 I hope it is and that it gets fixed!

Aug 30 2004