Thread overview
Can opCmp return a 'long' instead of 'int'?
Feb 16, 2014
Saurabh Das
Feb 16, 2014
Timon Gehr
Feb 16, 2014
Timon Gehr
Feb 16, 2014
bearophile
Feb 16, 2014
Timon Gehr
Feb 17, 2014
Saurabh Das
February 16, 2014
Hello,

The call signature for opCmp in a struct is:

struct S {
  int opCmp(ref const S s) const { ... }
}

int opCmp(ref const S s) const { return _val - s._val; }

This works fine if _val is 'int'. However, if _val is 'long' then subtracting 2 longs may not result in an int - and therefore I would have to replace the subtraction above with 2 comparison operators.

My question is: Can I rewrite opCmp to return a 'long', like:

struct S {
  long opCmp(ref const S s) const { return _val - s.val; }
}

This does compile and run correctly, but are there any hidden assumptions or requirements on the return value of opCmp that I should be aware of? Is there any reason that doing this may be not be wise?

Thanks,
Saurabh
February 16, 2014
On 02/16/2014 02:59 PM, Saurabh Das wrote:
>
> This does compile and run correctly, but are there any hidden
> assumptions or requirements on the return value of opCmp that I should
> be aware of? Is there any reason that doing this may be not be wise?

No, this is fine.
February 16, 2014
On 02/16/2014 04:13 PM, Timon Gehr wrote:
> On 02/16/2014 02:59 PM, Saurabh Das wrote:
>>
>> This does compile and run correctly, but are there any hidden
>> assumptions or requirements on the return value of opCmp that I should
>> be aware of? Is there any reason that doing this may be not be wise?
>
> No, this is fine.

To be more precise: Returning long is fine.

The subtraction trick does not work in general regardless of return type:

import std.stdio;
struct S{
    int d;
    int opCmp(S r){ return d - r.d; }
}

void main(){
    assert(S(1)<S(2)); // passes. ok.
    assert(S(int.min)>S(int.max)); // passes. oops.
}

February 16, 2014
Timon Gehr:

>     assert(S(1)<S(2)); // passes. ok.
>     assert(S(int.min)>S(int.max)); // passes. oops.

A possible solution is to add to Phobos (unless it's already there) a variadic templated funcion cmpBuilder() that accepts an even number of arguments, that are seen as pairs. Usage example:

struct Foo {
  int x, y;
  string s;
  int opCmp(in ref Foo r) {
    return cmpBuilder(x, r.x, y.abs, r.y.abs, s, r.s);
  }
}

Is this worth adding to Phobos?

Bye,
bearophile
February 16, 2014
On 02/16/2014 04:40 PM, bearophile wrote:
> Timon Gehr:
>
>>     assert(S(1)<S(2)); // passes. ok.
>>     assert(S(int.min)>S(int.max)); // passes. oops.
>
> A possible solution is to add to Phobos (unless it's already there) a
> variadic templated funcion cmpBuilder() that accepts an even number of
> arguments, that are seen as pairs. Usage example:
>
> struct Foo {
>    int x, y;
>    string s;
>    int opCmp(in ref Foo r) {
>      return cmpBuilder(x, r.x, y.abs, r.y.abs, s, r.s);
>    }
> }
>
> Is this worth adding to Phobos?
>
> Bye,
> bearophile

IMO no (lots of repetition), but forwarding opCmp is:

struct Foo{
    int x,y;
    string s;
    private @property order(){ return tuple(x, abs(y), s); }
    mixin OrderBy!order;
}

Furthermore, the language should be updated such that the built-in types are not special w.r.t. operators. Eg:

1.opBinary!"+"(2)
1.opCmp(2)

should work.

The following should be supported as well:

struct Foo{
    int x,y;
    string s;
    mixin OrderBy!(()=>tuple(x, abs(y), s));
}

(Currently DMD bans function literals as members.)
February 17, 2014
On Sunday, 16 February 2014 at 15:19:08 UTC, Timon Gehr wrote:
> On 02/16/2014 04:13 PM, Timon Gehr wrote:
>> On 02/16/2014 02:59 PM, Saurabh Das wrote:
>>>
>>> This does compile and run correctly, but are there any hidden
>>> assumptions or requirements on the return value of opCmp that I should
>>> be aware of? Is there any reason that doing this may be not be wise?
>>
>> No, this is fine.
>
> To be more precise: Returning long is fine.
>
> The subtraction trick does not work in general regardless of return type:
>
> import std.stdio;
> struct S{
>     int d;
>     int opCmp(S r){ return d - r.d; }
> }
>
> void main(){
>     assert(S(1)<S(2)); // passes. ok.
>     assert(S(int.min)>S(int.max)); // passes. oops.
> }

Right. I didn't expect that! So I shouldn't use it anyway. Thanks!

Saurabh