www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Operator overloading question

reply "Joseph Cassman" <jc7919 outlook.com> writes:
Please refer to http://dpaste.dzfl.pl/edit/b73ef2cd

The code is contrived but is trying to focus on overloading the 
"+" and "*" operators for a struct.

Here is the output.

/home/c215/c527.d(36): Error: incompatible types for ((x) + (y)): 
'Arithmetic!(int)' and 'Arithmetic!(int)'
/home/c215/c527.d(37): Error: 'x' is not of arithmetic type, it 
is a Arithmetic!(int)
/home/c215/c527.d(37): Error: 'y' is not of arithmetic type, it 
is a Arithmetic!(int)

I am trying to understand why there are errors at all.
Also why the error for line 36 is different from the error for 
line 37.

Thanks

Joseph
Jan 20 2013
parent reply "Nathan M. Swan" <nathanmswan gmail.com> writes:
On Monday, 21 January 2013 at 06:19:47 UTC, Joseph Cassman wrote:
 Please refer to http://dpaste.dzfl.pl/edit/b73ef2cd

 The code is contrived but is trying to focus on overloading the 
 "+" and "*" operators for a struct.

 Here is the output.

 /home/c215/c527.d(36): Error: incompatible types for ((x) + 
 (y)): 'Arithmetic!(int)' and 'Arithmetic!(int)'
 /home/c215/c527.d(37): Error: 'x' is not of arithmetic type, it 
 is a Arithmetic!(int)
 /home/c215/c527.d(37): Error: 'y' is not of arithmetic type, it 
 is a Arithmetic!(int)

 I am trying to understand why there are errors at all.
 Also why the error for line 36 is different from the error for 
 line 37.

 Thanks

 Joseph
The correct keyword is "opBinary", not "opbinary". Also, that's a link to editing the paste, viewing it is: http://dpaste.1azy.net/b73ef2cd
Jan 20 2013
next sibling parent "Joseph Cassman" <jc7919 outlook.com> writes:
On Monday, 21 January 2013 at 06:51:23 UTC, Nathan M. Swan wrote:
 On Monday, 21 January 2013 at 06:19:47 UTC, Joseph Cassman 
 wrote:
 Please refer to http://dpaste.dzfl.pl/edit/b73ef2cd

 The code is contrived but is trying to focus on overloading 
 the "+" and "*" operators for a struct.

 Here is the output.

 /home/c215/c527.d(36): Error: incompatible types for ((x) + 
 (y)): 'Arithmetic!(int)' and 'Arithmetic!(int)'
 /home/c215/c527.d(37): Error: 'x' is not of arithmetic type, 
 it is a Arithmetic!(int)
 /home/c215/c527.d(37): Error: 'y' is not of arithmetic type, 
 it is a Arithmetic!(int)

 I am trying to understand why there are errors at all.
 Also why the error for line 36 is different from the error for 
 line 37.

 Thanks

 Joseph
The correct keyword is "opBinary", not "opbinary". Also, that's a link to editing the paste, viewing it is: http://dpaste.1azy.net/b73ef2cd
Nice when it's an easy fix. Appreciate the pointer on dpaste too. Joseph
Jan 20 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Nathan M. Swan:

 The correct keyword is "opBinary", not "opbinary".
The compiler must give an error message easy to understand in similar wrong cases.
 http://dpaste.1azy.net/b73ef2cd
This is your code: Arithmetic opbinary(string op)(Arithmetic rhs) { static if(op == "+") return add(rhs); static if(op == "*") return mul(rhs); else static assert(0, "Operator "~op~" not implemented"); } I like to add template constraints, where possible: Arithmetic opbinary(string op)(Arithmetic rhs) const pure nothrow if (op == "+" || op == "*") Bye, bearophile
Jan 21 2013
parent reply "mist" <none none.none> writes:
Do you want to discuss it? :) I have noticed that phobos style 
guidelines favor constraints heavily over static asserts but this 
exactly the example when I am uneasy about such choice: static 
assert can both provide more user-friendly error message here and 
remove some code duplication.

On Monday, 21 January 2013 at 12:27:35 UTC, bearophile wrote:
 Nathan M. Swan:

 The correct keyword is "opBinary", not "opbinary".
The compiler must give an error message easy to understand in similar wrong cases.
 http://dpaste.1azy.net/b73ef2cd
This is your code: Arithmetic opbinary(string op)(Arithmetic rhs) { static if(op == "+") return add(rhs); static if(op == "*") return mul(rhs); else static assert(0, "Operator "~op~" not implemented"); } I like to add template constraints, where possible: Arithmetic opbinary(string op)(Arithmetic rhs) const pure nothrow if (op == "+" || op == "*") Bye, bearophile
Jan 21 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/21/2013 08:32 AM, mist wrote:

 phobos style
 guidelines favor constraints heavily over static asserts but this
 exactly the example when I am uneasy about such choice: static assert
 can both provide more user-friendly error message here and remove some
 code duplication.
Agreed but there is a problem with 'static assert' in the implementation: We don't know what user code has caused the issue. (It is a common problem in C++ templated libraries that a hard-to-understand compilation error is produced from inside a library function template.) D's template constraints move the compilation error to the exact place of the user code. void foo(string s)() if ((s == "hello") || (s == "goodbye")) { // ... } void main() { foo!"howdy"(); // <-- compilation error on this line } It is better: Error: template instance foo!("howdy") foo!("howdy") does not match template declaration foo(string s)() if (s == "hello" || s == "goodbye") To be honest, it is kind of obvious in this simple case but sometimes the cause of the error is still hard to understand even with template consraints. Ali
Jan 21 2013
parent reply "mist" <none none.none> writes:
Hm, but why can't static assert provide an instantiation trace? I 
can live without error message but duplicating same condition 
twice (one time being part of implementation) hurts my eyes :(

On Monday, 21 January 2013 at 17:16:22 UTC, Ali Çehreli wrote:
 On 01/21/2013 08:32 AM, mist wrote:

 phobos style
 guidelines favor constraints heavily over static asserts but
this
 exactly the example when I am uneasy about such choice:
static assert
 can both provide more user-friendly error message here and
remove some
 code duplication.
Agreed but there is a problem with 'static assert' in the implementation: We don't know what user code has caused the issue. (It is a common problem in C++ templated libraries that a hard-to-understand compilation error is produced from inside a library function template.) D's template constraints move the compilation error to the exact place of the user code. void foo(string s)() if ((s == "hello") || (s == "goodbye")) { // ... } void main() { foo!"howdy"(); // <-- compilation error on this line } It is better: Error: template instance foo!("howdy") foo!("howdy") does not match template declaration foo(string s)() if (s == "hello" || s == "goodbye") To be honest, it is kind of obvious in this simple case but sometimes the cause of the error is still hard to understand even with template consraints. Ali
Jan 21 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/21/2013 10:02 AM, mist wrote:
 Hm, but why can't static assert provide an instantiation trace? I can
 live without error message
I forgot to mention that template constraints take part in choosing the implementation as well: void foo(string s)() if ((s == "hello") || (s == "goodbye")) { // ... } void foo(string s)() if (s == "howdy") { // ... } void main() { foo!"howdy"(); // not an error: goes to special implementation foo!"merhaba"(); // error: no implementation at all } In order to achieve the same goal without template constraints we have two options: 1) Template specialization, which I don't think is not valid for non-type template parameters like string: void foo(string s == "hello")() // ERROR; I don't think possible { // ... } 2) 'static if' in the implementation: void foo(string s)() { static if ((s == "hello") || (s == "goodbye")) { // ... } else static if (s == "howdy") { // ... } else { static assert(false, "Invalid string " ~ s); } } void main() { foo!"howdy"(); foo!"merhaba"(); } You are right though, dmd does produce useful information for this simple case: Error: static assert "Invalid string merhaba" instantiated from here: foo!("merhaba") The only shortcoming that I see in this case is that the implementations for different string values are inside the same function template.
 but duplicating same condition twice (one
 time being part of implementation) hurts my eyes :(
Can you elaborate. I don't see the duplication. Ali
Jan 21 2013
next sibling parent "mist" <none none.none> writes:
On Monday, 21 January 2013 at 18:53:08 UTC, Ali Çehreli wrote:
 ...
 Can you elaborate. I don't see the duplication.

 Ali
First we check that parameter is one of allowed ones in constraint. Then we do the very same check using the very same operator list to actually make a right dispatch. Looks wrong to me, we shouldn't need to. I need to clarify though: I am perfectly aware that constraints are superior solution in many cases, especially when it comes to multiple overloads for library snippets. But exactly in given example static assert feels as better suited.
Jan 21 2013
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/21/2013 07:53 PM, Ali Çehreli wrote:
 ...

 void foo(string s == "hello")() // ERROR; I don't think possible
 {
      // ...
 }
void foo(string s : "hello")(){ // ... }
Jan 22 2013