C++ Logo

std-proposals

Advanced search

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

From: Chris Gary <cgary512_at_[hidden]>
Date: Wed, 27 Sep 2023 01:30:19 -0600
>
> if (posix_fallocate(fd, 0, size)) {
>
> errno is not set.


Well, that is horrible. Something might have fixed POSIX like... making
entry points too long to invoke in a conditional and then every example of
the API involve "NTSTATUS status = ..." then "if(NT_SUCCESS( status ))"...
Though I'm not trying to sing anyone's praises here, I actually find that
sort of "forced error handling" much clearer than relying on implicit
behavior. Of course it can be made just as bad and unstable. However,
neither ERRNO or NTSTATUS are in any way the same as a 3 (or 4) element set.

It is not that POSIX APIs are inconsistent from one to another, it is that
they are *documented* and users *don't read the* *documentation*. I'm no
saint here either, though this is also why we test. No degree of semantic
enforcement is going to spare one from making mistakes like those. Worse
still, their implementations may be inconsistent or unstable to the extent
of forcing incorrect usage.

Combination is particularly important for generic code: how do you write
> operator<=> for std::vector<T> or std::tuple<T...> ? For tuples, it's a
> heterogeneous list, so the types may be weakly ordered, strongly ordered or
> only partially ordered. So what is the result of the three-way compare?
>

Straightforwardly apply <=> to each pair of members in succession, like a
string. Apply common_type to both before comparing in a tuple (this can
apply to any structure). Take the first result that isn't equal. If they
were all equal, then the result of the composition is equal. This exact
same idea applies to multiple precision integers (or even in string
comparison), where despite the data being heterogeneous, the comparison
still has a consistent interpretation as "sign of difference". For example,
you can envision the individual sequences of bytes in PODs contained in
tuples as just plain integers.

If a particular sort is needed, like case-insensitivity, this requires a
transformation to be applied. Wherever that transformation is applied, even
if it is just setting a flag, is also where the change in the nature of the
comparison can be noted. It is possible to change the sorting category of
strings at runtime by just changing locales. A statically-compiled,
semantically rich 3-way comparison enum isn't going to stop someone from
setting a flag. As another example from numerics: Change a rounding mode at
runtime. Now going from something like an MP::Rational to a double has a
slightly different ordering over the doubles. How is this change in
behavior enforced? By a predicate separate from both MP::Rational and
double, which is also going to implement some kind of contextual awareness
of this fact.

It is possible to keep std::strong_ordering around. Just formally allow
<signed-int> operator<=>, and let the compiler do the rest. The alternative
is really just saving around 12 lines of code per thing that needs a full
suite of comparison operators.

On Tue, Sep 26, 2023 at 11:27 PM Thiago Macieira via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> On Tuesday, 26 September 2023 20:34:16 PDT Chris Gary via Std-Proposals
> wrote:
> > I fail to see why a strongly-typed ternary, mandatory for use with <=>,
> > provides an adequate solution to this problem. Especially where the
> > operator is user-defined.
> > All it does is create what I consider to be a nuisance of a dependency.
>
> Because that's not the problem it solves.
>
> No one is arguing that four values can't be represented in int. No one is
> arguing that optimal code can't be generated.
>
> The use of a strong type solves two problems that int doesn't: semantic
> and
> combination. Semantic allows code to know the difference between equality
> in
> strongly-comparable types and equivalence in weakly-ordered ones. You may
> not
> care about that difference, but other people do. The strong typing also
> allows
> one to know whether the result can be unordered or not: if it can't be
> unordered, you don't need to implement the lookup tables you described at
> all.
>
> Combination is particularly important for generic code: how do you write
> operator<=> for std::vector<T> or std::tuple<T...> ? For tuples, it's a
> heterogeneous list, so the types may be weakly ordered, strongly ordered
> or
> only partially ordered. So what is the result of the three-way compare?
>
> Moreover, semantic gives meaning where int doesn't. Let's take these two
> very,
> very similar functions that return int from the C / POSIX library:
>
> int memcmp(const void *, const void *, size_t);
> int bcmp(const void *, const void *, size_t);
>
> As we all know, memcmp() performs a three-way comparison and returns
> negative,
> zero, and positive for less than, equal, and greater than byte
> comparisons.
> bcmp() does not. It returns zero for equal and non-zero otherwise. But
> does
> the return type convey that meaning? No. Will people mistake one for the
> other? They most surely will.
>
> And have. In fact, since in most C libraries bcmp() is implemented as an
> alias
> to memcmp(), it has returned negative and positive as people might have
> expected. This is so bad that when glibc attempted to implement a slightly
> faster bcmp() that didn't return negative/positive, it broke all sorts of
> user
> code. So glibc added __memcmpeq() instead.
>
> Plain integers are bad to convey semantic meaning. I'm just going to give
> another example that we found lurking in our codebase for 3 years:
>
> if (posix_fallocate(fd, 0, size)) {
> int saved_errno = errno;
> log_warning("could not create temporary file: %s",
> strerror(errno));
> close(fd);
> return -saved_errno;
> }
>
> See if you can spot the error.
>
> PS: it's slightly ironic that memcmp() would not be a good example of your
> suggestion, in spite its returning an int.
> --
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
> Software Architect - Intel DCAI Cloud Engineering
>
>
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2023-09-27 07:30:34