C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Let spaceship return an int

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Wed, 27 Sep 2023 21:13:29 -0400
On Wed, Sep 27, 2023 at 7:45 PM Chris Gary via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>>
>> You've repeated yourself without thinking about what I wrote. You've answered
>> for equality. Now think about the other operators: how does it implement "is
>> less" for the type I proposed earlier? Mind you, it is strongly ordered and
>> memcmp() only returns sign, not constraining itself to -1, 0, 1.
>
>
> What I've stated covers all cases of <=>. I keep repeating myself because I keep reading the same appeal to convention over and over again.
>
> The issues of composability that keep coming up are the same as the distinction in byte ordering. LE integers compose regardless of limb size, BE do not. For an LE thing made out of smaller BE things, value comparisons are needed and so on.
>
> Memberwise comparison is already implemented in exactly the same way as I've described.
> Its even in the documentation:
>>
>> Defaulted three-way comparison
>>
>> The default operator<=> performs lexicographical comparison by successively comparing the base (left-to-right depth-first) and then non-static member (in declaration order) subobjects of T to compute <=>, recursively expanding array members (in order of increasing subscript), and stopping early when a not-equal result is found, that is:
>
>
> https://godbolt.org/z/7xfKrKfTb
>
> The same as memberwise assignment, default construction, etc...
> Takes the least restrictive ordering, or partial_order.
> It looks like all things are in general partial_order, if that helps clarify again.
>
> saturate_to_tbl() -> {-1,0,1}|{-2}. You can call the members whatever you'd like. Everything not {a,b,c} is an error and maps to "explode", "idunno", or "hot_potato".
> I don't advise building general predicates on the de-facto definition of memcmp.

But that is *exactly* what people will do. All you've done is
introduce fragility to the system, where `int` in one place doesn't
really mean `int`.

There is a *very* long-standing convention in C code for 3-way
comparison functions to return a signed integer where the sign
represents the directionality of the comparison. And I'm not just
talking about the standard C library functions like `memcmp` and
`strlen`. Pretty much any 3-way comparison function that returns an
`int` *does not* require that the integer is on the range [-1, 1]. All
values are valid, and the only thing you're expected to test is the
sign (or zero).

C++ explicitly didn't want to engage with this convention for its
3-way comparison operator. So they created a *new* convention: the
ordering types. It's a convention that gives you a *compile error* if
you try to directly return the result of `memcmp`, but if you return
`memcmp(...) <=> 0`, it works fine.

That's what good design looks like: noisy errors when you do it wrong,
and easy to do it right.

You are trying to invent your *own* convention and crowbar it into
C++. A convention that is syntactically identical to the established C
convention, but is semantically incompatible with it. And because of
that, there is no compile-time test to know whether you're using the
C-convention or the Chris-convention. You can do it wrong and get
silently working code... until someone does the wrong thing and it
doesn't work anymore.

That's what bad design looks like: errors are allowed to creep into
code and make it appear to work... until it doesn't, and with few
pointers to where things went wrong.

Though it's interesting that you're suddenly OK with including a
header for your `std::saturate_to_tbl` function. You *are* proposing
adding such a function to the standard library, right? Because your
proposal is incomplete without it, as it would be unable to interact
with C convention-based code. Unlike the status quo, where all you
have to do is apply `<=> 0`.

Received on 2023-09-28 01:13:41