Jump to page: 1 2
Thread overview
opCmp with template type not working.
Nov 03, 2020
Jonathan Levi
Nov 03, 2020
rikki cattermole
Nov 03, 2020
user1234
Nov 03, 2020
Jonathan Levi
Nov 03, 2020
ag0aep6g
Nov 04, 2020
Paul Backus
Nov 08, 2020
Paul Backus
November 03, 2020
This is not working as expected:
> bool opCmp(string op, U)(U rhs) {

As it does work with:
> auto opBinary(string op, U)(U rhs) {


With:

> struct X {
>     int x;
>     auto opBinary(string op, U)(U rhs) {
>             return mixin("x "~op~" rhs");
>         }
>     bool opCmp(string op, U)(U rhs) {
>         return mixin("x "~op~" rhs");
>     }
> }

This compiles:
> X(5) + 4
This does not:
> X(5) < 4

Full example code: https://run.dlang.io/is/Beflkt

Is this a Bug?

November 03, 2020
Two questions:

1) Why is opCmp returning a bool?
2) Why does opCmp have a template parameter called `op`?

https://dlang.org/spec/operatoroverloading.html#compare
November 03, 2020
On Tuesday, 3 November 2020 at 02:55:46 UTC, Jonathan Levi wrote:
> This is not working as expected:
>> bool opCmp(string op, U)(U rhs) {
>
> As it does work with:
>> auto opBinary(string op, U)(U rhs) {
>
>
> With:
>
>> struct X {
>>     int x;
>>     auto opBinary(string op, U)(U rhs) {
>>             return mixin("x "~op~" rhs");
>>         }
>>     bool opCmp(string op, U)(U rhs) {
>>         return mixin("x "~op~" rhs");
>>     }
>> }
>
> This compiles:
>> X(5) + 4
> This does not:
>> X(5) < 4
>
> Full example code: https://run.dlang.io/is/Beflkt
>
> Is this a Bug?

opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)
November 03, 2020
On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:
> opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)

Um, I missed that.  Man, I have some old errors in my code.  I had opCmp implemented that way for a while, and apparently never tested or used it.  I see that now in the spec.


November 03, 2020
On 03.11.20 04:07, user1234 wrote:
> opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)

Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound.

Example: int.min < 1, but int.min - 1 > 0.
November 03, 2020
On 11/3/20 1:56 AM, ag0aep6g wrote:
> On 03.11.20 04:07, user1234 wrote:
>> opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)
> 
> Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound.
> 
> Example: int.min < 1, but int.min - 1 > 0.

druntime does it for integrals smaller than int. For others, you can do:

return (a > b) - (b < a);
November 03, 2020
On 11/3/20 8:48 AM, Andrei Alexandrescu wrote:
> On 11/3/20 1:56 AM, ag0aep6g wrote:
>> On 03.11.20 04:07, user1234 wrote:
>>> opCmp should return a signed integer. This allows to match well with the x86 flag register and do fast comparison with integers types (in which case just substract rhs to lhs and you're good)
>>
>> Doing comparison by subtracting is a cute idea, but it doesn't actually work in general because of wraparound.
>>
>> Example: int.min < 1, but int.min - 1 > 0.
> 
> druntime does it for integrals smaller than int. For others, you can do:
> 
> return (a > b) - (b < a);

Ehm.

return (a > b) - (a < b);

November 04, 2020
On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:

> opCmp should return a signed integer.
No. opCmp should return a float, to have all 4 possible comparison results available:
greater (1)
lower (-1)
equal (0) and
not comparable (NaN)

Especially the last one is necessary if you like to have opCmp defined on some not completely ordered set.
November 04, 2020
On Wednesday, 4 November 2020 at 09:01:21 UTC, Dominikus Dittes Scherkl wrote:
> On Tuesday, 3 November 2020 at 03:07:14 UTC, user1234 wrote:
>
>> opCmp should return a signed integer.
> No. opCmp should return a float, to have all 4 possible comparison results available:
> greater (1)
> lower (-1)
> equal (0) and
> not comparable (NaN)
>
> Especially the last one is necessary if you like to have opCmp defined on some not completely ordered set.

opCmp can return whatever you want, as long as it is comparable with 0 using the `<`, `>`, `<=`, and `>=` operators:

https://dlang.org/spec/operatoroverloading.html#compare

IMO there's no reason to use a floating-point number unless you specifically need partial ordering. For the common case of a totally-ordered type, a signed integer is fine.
November 08, 2020
On Wednesday, 4 November 2020 at 15:51:04 UTC, Paul Backus wrote:
> opCmp can return whatever you want, [...]
> IMO there's no reason to use a floating-point number unless you specifically need partial ordering. For the common case of a totally-ordered type, a signed integer is fine.

Yeah, but int is 32 bit, same as float. So why use a type that restricts the use cases without any benefit?
Simply always use float, so you have no changes if you later detect that your type to compare is in fact _not_ totally ordered (e.g. has some special cases). And beliefe me, for most types you will earlier or later detect, that they are not totally ordered.
Today when I look, most libraries do some ugly and non-performant special casing because their comparison operators didn't handle the not-comparable case correctly. In D we can do better, as we CAN handle it. So everybody should be taught to use float as the result of opCmp. The earlier we do it correct, the better for the language!

« First   ‹ Prev
1 2