Jump to page: 1 24  
Page
Thread overview
February 12
With opBinary and opUnary it is possible to create types that span the binary and unary operators. However opEquals can only be used to types that compare for equality not inequality, since a == b -> a.opEquals(b) can return whatever type it likes but a == b -> !(a.opEquals(b)) returns a bool. opCmp can't be used at all since a <=> b -> a.opCmp(b) <=> 0 which evaluates to a bool.

I propose that in addition to the current (non-template) forms of opCmp/opEquals

struct A { bool opEquals(A rhs); int opCmp(A rhs); }

we allow

struct B
{
    T opEquals(string op)(B rhs); // op is "<" "<=" etc.
    T opCmp(string op)(B rhs);    // op is "==" "!="
}

where T is any arbitrary type.

see also https://github.com/k3kaimu/dranges/blob/master/source/dranges/_lambda.d
February 11
On Monday, February 11, 2019 9:15:34 PM MST Nicholas Wilson via Digitalmars- d wrote:
> With opBinary and opUnary it is possible to create types that
> span the binary and unary operators. However opEquals can only be
> used to types that compare for equality not inequality, since a
> == b -> a.opEquals(b) can return whatever type it likes but a ==
> b -> !(a.opEquals(b)) returns a bool. opCmp can't be used at all
> since a <=> b -> a.opCmp(b) <=> 0 which evaluates to a bool.
>
> I propose that in addition to the current (non-template) forms of
> opCmp/opEquals
>
> struct A { bool opEquals(A rhs); int opCmp(A rhs); }
>
> we allow
>
> struct B
> {
>      T opEquals(string op)(B rhs); // op is "<" "<=" etc.
>      T opCmp(string op)(B rhs);    // op is "==" "!="
> }
>
> where T is any arbitrary type.
>
> see also https://github.com/k3kaimu/dranges/blob/master/source/dranges/_lambda.d

Weren't D's overloaded operators designed specifically with the idea that they _wouldn't_ support stuff like expression templates? They're supposed to emulate the built-in types with how normal equality and the like works, not be used for creating new syntax.

- Jonathan M Davis



February 12
On Tuesday, 12 February 2019 at 04:42:39 UTC, Jonathan M Davis wrote:
> Weren't D's overloaded operators designed specifically with the idea that they _wouldn't_ support stuff like expression templates?

Well you can but only with non-relational operators. IIRC they were designed s.t. you only needed to define one function to get a suite of operators (c.f. C++).

> They're supposed to emulate the built-in types with how normal equality and the like works, not be used for creating new syntax.

Well the syntax is still the same, just the meaning is different.
February 12
On Tuesday, 12 February 2019 at 04:15:34 UTC, Nicholas Wilson wrote:
> With opBinary and opUnary it is possible to create types that span the binary and unary operators. However opEquals can only be used to types that compare for equality not inequality, since a == b -> a.opEquals(b) can return whatever type it likes but a == b -> !(a.opEquals(b)) returns a bool. opCmp can't be used at all since a <=> b -> a.opCmp(b) <=> 0 which evaluates to a bool.
>
> I propose that in addition to the current (non-template) forms of opCmp/opEquals
>
> struct A { bool opEquals(A rhs); int opCmp(A rhs); }
>
> we allow
>
> struct B
> {
>     T opEquals(string op)(B rhs); // op is "<" "<=" etc.
>     T opCmp(string op)(B rhs);    // op is "==" "!="
> }
>
> where T is any arbitrary type.
>
> see also https://github.com/k3kaimu/dranges/blob/master/source/dranges/_lambda.d

This looks super cool!!

Can a workaround for the opEquals be that a.opEquals(b) produces a ProxyType and then ProxyType.opUnary gets you to where you want to go?
February 12
On 12.02.19 05:15, Nicholas Wilson wrote:
> With opBinary and opUnary it is possible to create types that span the binary and unary operators. However opEquals can only be used to types that compare for equality not inequality, since a == b -> a.opEquals(b) can return whatever type it likes but a == b -> !(a.opEquals(b)) returns a bool. opCmp can't be used at all since a <=> b -> a.opCmp(b) <=> 0 which evaluates to a bool.
> 
> I propose that in addition to the current (non-template) forms of opCmp/opEquals
> 
> struct A { bool opEquals(A rhs); int opCmp(A rhs); }
> 
> we allow
> 
> struct B
> {
>      T opEquals(string op)(B rhs); // op is "<" "<=" etc.
>      T opCmp(string op)(B rhs);    // op is "==" "!="
> }
> 
> where T is any arbitrary type.
> 
> see also https://github.com/k3kaimu/dranges/blob/master/source/dranges/_lambda.d

Ideally those would both be cases of opBinary, but I guess your proposal has better backwards compatibility.
February 12
On Monday, February 11, 2019 11:07:43 PM MST Nicholas Wilson via Digitalmars-d wrote:
> > They're supposed to emulate the built-in types with how normal equality and the like works, not be used for creating new syntax.
>
> Well the syntax is still the same, just the meaning is different.

Having the meaning be different is precisely the problem. It's using the syntax for something _other_ than what it's intended for. It's just supposed to be a way to have user-defined types emulate the operations of built-in types. Walter has mentioned time and time again how he thinks that stuff like << in C++ where they made the operators mean something completely different than what they mean for built-in types was a big mistake, and personally, I agree. If it were up to me, it wouldn't even be legal to have opEquals return anything other than bool. In fact, I actually thought that we'd fixed it at one point so that it _did_ have to be bool, but I saw a post not that long ago where someone had an example that compiled where it returned something else. So, I guess that the compiler isn't quite that strict at the moment. Either way, I think that Walter has made it pretty clear that overloaded operators are not intended for stuff like DSLs or expression templates, and if you try to alter overloaded operators to make them work better for expression templates or the like, I would fully expect him to veto it. But I guess that we'll see his response soon enough if you try to push this.

- Jonathan M Davis



February 12
On Tuesday, 12 February 2019 at 10:37:22 UTC, Jonathan M Davis wrote:
> Having the meaning be different is precisely the problem. It's using the syntax for something _other_ than what it's intended for. It's just supposed to be a way to have user-defined types emulate the operations of built-in types. Walter has mentioned time and time again how he thinks that stuff like << in C++ where they made the operators mean something completely different than what they mean for built-in types was a big mistake, and personally, I agree.

I agree using << for I/O is stupid.

> Either way, I think that Walter has made it pretty clear that overloaded operators are not intended for stuff like DSLs or expression templates, and if you try to alter overloaded operators to make them work better for expression templates or the like, I would fully expect him to veto it.

Link?

> But I guess that we'll see his response soon enough if you try to push this.

The use case is e.g. building a DB query predicate where == still means equality not e.g. I/O, it just isn't evaluated directly. The fact is you can already use it for arithmetic to build e.g. linear algebra expression templates, and you can use == predicates but not != or any of the ordering comparisons is inconsistent arbitrary and annoying.
February 12
On Tuesday, 12 February 2019 at 11:35:28 UTC, Nicholas Wilson wrote:
> On Tuesday, 12 February 2019 at 10:37:22 UTC, Jonathan M Davis wrote:
>> Having the meaning be different is precisely the problem. It's using the syntax for something _other_ than what it's intended for. It's just supposed to be a way to have user-defined types emulate the operations of built-in types. Walter has mentioned time and time again how he thinks that stuff like << in C++ where they made the operators mean something completely different than what they mean for built-in types was a big mistake, and personally, I agree.
>
> I agree using << for I/O is stupid.

I've never understood this argument. I've never met anyone who was confused by this. Personally, I read it as "shove". C++20 ranges use `|` as a pipe operator instead of bitwise or, and not only does it make sense, I don't think anybody's complaining about that either.

> The use case is e.g. building a DB query predicate where == still means equality not e.g. I/O, it just isn't evaluated directly. The fact is you can already use it for arithmetic to build e.g. linear algebra expression templates, and you can use == predicates but not != or any of the ordering comparisons is inconsistent arbitrary and annoying.

Agreed.
February 12
On 2019-02-12 12:35, Nicholas Wilson wrote:

> The use case is e.g. building a DB query predicate where == still means equality not e.g. I/O, it just isn't evaluated directly. The fact is you can already use it for arithmetic to build e.g. linear algebra expression templates, and you can use == predicates but not != or any of the ordering comparisons is inconsistent arbitrary and annoying.

I like it. I would like to be able to do this with DB queries as well. The alternative would be AST macros, but that is not likely to be accepted either.

-- 
/Jacob Carlborg
February 12
On Tuesday, February 12, 2019 4:35:28 AM MST Nicholas Wilson via Digitalmars-d wrote:
> On Tuesday, 12 February 2019 at 10:37:22 UTC, Jonathan M Davis wrote:
> > Either way, I think that Walter has made it pretty clear that overloaded operators are not intended for stuff like DSLs or expression templates, and if you try to alter overloaded operators to make them work better for expression templates or the like, I would fully expect him to veto it.
>
> Link?

He's said as much on several occasions over the years, but here's a link to one such comment:

https://forum.dlang.org/post/nsffdd$1h6m$1@digitalmars.com

- Jonathan M Davis



« First   ‹ Prev
1 2 3 4