January 12, 2016
On Tuesday, 12 January 2016 at 19:46:47 UTC, John Colvin wrote:
> On Tuesday, 12 January 2016 at 19:44:18 UTC, Fool wrote:
>> Non-reflexive '<=' does not make any sense at all.
>
> It might be a bit of a mess, agreed, but nonetheless:
>
> assert(!(float.nan <= float.nan));

Agreed, but in case of float '<=' is not an order at all.
January 12, 2016
On Tuesday, 12 January 2016 at 19:48:35 UTC, Fool wrote:
> On Tuesday, 12 January 2016 at 19:46:47 UTC, John Colvin wrote:
>> On Tuesday, 12 January 2016 at 19:44:18 UTC, Fool wrote:
>>> Non-reflexive '<=' does not make any sense at all.
>>
>> It might be a bit of a mess, agreed, but nonetheless:
>>
>> assert(!(float.nan <= float.nan));
>
> Agreed, but in case of float '<=' is not an order at all.

By the way, that implies that the result of sorting an array of float by default comparison is undefined unless the array does not contain NaN.

January 12, 2016
On Tuesday, 12 January 2016 at 19:28:36 UTC, Andrei Alexandrescu wrote:
> On 01/12/2016 02:13 PM, John Colvin wrote:
>> a<=b and b<=a must also be false.
>
> Would the advice "Only use < and == for partially-ordered data" work? -- Andrei

If by that you mean "Only use <= or >= on data that defines a total ordering"* I guess it would work, but it has some pretty big downsides:

1) Annoying to use.
2) You have to use the opCmp return 0 (which normally means a[<>]=b && b[<>]=a) to mean "not comparable".
3) Not enforceable. Because of 2 you'll always get true if you use >= or <= on any a pair that doesn't have a defined ordering.
4) inefficient (have to do both < and == separately which can be a lot more work than <=).

*would be safer to say "types that define", but strictly speaking...
January 12, 2016
On 01/12/2016 03:01 PM, John Colvin wrote:
> On Tuesday, 12 January 2016 at 19:28:36 UTC, Andrei Alexandrescu wrote:
>> On 01/12/2016 02:13 PM, John Colvin wrote:
>>> a<=b and b<=a must also be false.
>>
>> Would the advice "Only use < and == for partially-ordered data" work?
>> -- Andrei
>
> If by that you mean "Only use <= or >= on data that defines a total
> ordering"* I guess it would work, but it has some pretty big downsides:
>
> 1) Annoying to use.
> 2) You have to use the opCmp return 0 (which normally means a[<>]=b &&
> b[<>]=a) to mean "not comparable".
> 3) Not enforceable. Because of 2 you'll always get true if you use >= or
> <= on any a pair that doesn't have a defined ordering.
> 4) inefficient (have to do both < and == separately which can be a lot
> more work than <=).
>
> *would be safer to say "types that define", but strictly speaking...

I'd be in favor of giving people the option to disable the use of <= and >= for specific data. It's a simple and logical approach. -- Andrei

January 12, 2016
On Tuesday, 12 January 2016 at 20:04:26 UTC, Andrei Alexandrescu wrote:
> I'd be in favor of giving people the option to disable the use of <= and >= for specific data. It's a simple and logical approach. -- Andrei

But doesn't the symbol <= originate from ORing < and = ?
January 12, 2016
On Tuesday, 12 January 2016 at 20:10:11 UTC, Fool wrote:
> But doesn't the symbol <= originate from ORing < and = ?

'=' in the mathematical sense.
January 12, 2016
On 01/12/2016 03:10 PM, Fool wrote:
> On Tuesday, 12 January 2016 at 20:04:26 UTC, Andrei Alexandrescu wrote:
>> I'd be in favor of giving people the option to disable the use of <=
>> and >= for specific data. It's a simple and logical approach. -- Andrei
>
> But doesn't the symbol <= originate from ORing < and = ?

D uses !(b < a) for a <= b. We can invent notation to disallow that rewrite.

Anyhow the use of <, >, <=, and >= for partially ordered types is bound to be less than smooth. Math papers and books often use other notations (such as rounded or square less-than) to denote operators for partially ordered data, exactly because denoting them with the classic notation may confuse the reader.


Andrei

January 12, 2016
On Tuesday, 12 January 2016 at 20:25:25 UTC, Andrei Alexandrescu wrote:
> D uses !(b < a) for a <= b. We can invent notation to disallow that rewrite.
>
> Anyhow the use of <, >, <=, and >= for partially ordered types is bound to be less than smooth. Math papers and books often use other notations (such as rounded or square less-than) to denote operators for partially ordered data, exactly because denoting them with the classic notation may confuse the reader.
>
>
> Andrei

It is perfectly fine to use !(b < a) for a <= b. But as John has pointed out this is sensible only if '<=' is total.

Personally, I'm unsure about the best solution for D. I understand Walter's argument to 'keep it simple' and do not support non-total opCmp. On the other hand it is a bit unsatisfactory that one cannot write a custom type that behaves like float.
January 12, 2016
On 01/12/2016 07:27 PM, John Colvin wrote:
> ...


struct S{
    auto opCmp(S rhs){ return float.nan; }
    bool opEquals(S rhs){ return false; }
}

unittest{
    S a,b;
    assert(!(a==b));
    assert(!(a<b));
    assert(!(a<=b));
    assert(!(a>b));
    assert(!(a>=b));
}

January 12, 2016
On Tuesday, 12 January 2016 at 20:04:26 UTC, Andrei Alexandrescu wrote:
> On 01/12/2016 03:01 PM, John Colvin wrote:
>> On Tuesday, 12 January 2016 at 19:28:36 UTC, Andrei Alexandrescu wrote:
>>> On 01/12/2016 02:13 PM, John Colvin wrote:
>>>> a<=b and b<=a must also be false.
>>>
>>> Would the advice "Only use < and == for partially-ordered data" work?
>>> -- Andrei
>>
>> If by that you mean "Only use <= or >= on data that defines a total
>> ordering"* I guess it would work, but it has some pretty big downsides:
>>
>> 1) Annoying to use.
>> 2) You have to use the opCmp return 0 (which normally means a[<>]=b &&
>> b[<>]=a) to mean "not comparable".
>> 3) Not enforceable. Because of 2 you'll always get true if you use >= or
>> <= on any a pair that doesn't have a defined ordering.
>> 4) inefficient (have to do both < and == separately which can be a lot
>> more work than <=).
>>
>> *would be safer to say "types that define", but strictly speaking...
>
> I'd be in favor of giving people the option to disable the use of <= and >= for specific data. It's a simple and logical approach. -- Andrei

Having thought about this a bit more, it doesn't fix the problem:

It doesn't enable custom float types that are on par with builtins, doesn't enable transparent "missing-value" types and doesn't make tsbockmans checked integer types (or other custom types) work properly and transparently with builtin floats. The points 1, 2 and 4 from above still stand. Also - the big problem - it requires antisymmetry, which means no preorders.

One of the great things about D's opCmp and opEquals is that it separates `a==b` from `a<=b && b<=a`, which enables it to express types without antisymmetric ordering (see original post for examples), what you're describing would be a frustrating situation where you have to choose between breaking antisymmetry and breaking totality, but never both.

Please consider the second design I proposed? It's small, simple, has no impact on existing code and works in the right direction (library types can emulate / act as replacements for builtins) as opposed to the other way (library types are second class).