Date: Mon, 12 Mar 2018 17:22:12 -0700
On 3/12/18, Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]> wrote:
> On Mar 12, 2018, Lawrence Crowl <Lawrence_at_[hidden]> wrote:
>> So the application intended modular arithmetic? I was concerned about
>> the normal case where 'unsigned' is used to constrain the value range,
>> not to get modular arithmetic.
>
> IMNSHO, if anyone is using unsigned types "to constrain the value range,"
> they are doing computers wrong. That is *not* what signed vs. unsigned
> types are for.
I note that size_t is unsigned to constrain the value range, not to obtain
modular arithmetic.
> As Lawrence himself wrote earlier in this thread:
>> If integer overflow is undefined behavior, then it is wrong. Tools can
>> detect wrong programs and report them.
>
> The contrapositive is: "If the programmer is using a type where integer
> overflow is well-defined to wrap, then we can assume that the program
> relies on that wrapping behavior (because there would otherwise be a
> strong incentive for the programmer to use a type that detects and
> reports unintended overflow)."
Yes. For the most part, programmers should be explicit when they want
anything other than mathematical integers.
> The original design for the STL contained the "unsigned for value range"
> antipattern. Consequently, they ran into trouble immediately: for
> example, `std::string::find
> <https://en.cppreference.com/w/cpp/string/basic_string/find>` returns an
> index into the string, naturally of type `std::string::size_type`. But
> size_type is unsigned! So instead of returning "negative 1" to indicate
> the "not found" case, they had to make it return `size_type(-1)`, a.k.a.
> `std::string::npos` -- which is a positive value! This means that
> callers have to write cumbersome things such as
>
> if (s.find('k') != std::string::npos)
>
> where it would be more natural to write
>
> if (s.find('k') >= 0)
I won't disagree with the easier syntax of the latter, but I note that
the function itself is returning two things: the search status, and iff
successful the index of the found object.
> This is sort of parallel to my quotation of Lawrence above: If every
> possible value in the domain of a given type is a valid output (e.g.
> from `find`), then there is no value left over with which the function
> can signal failure at runtime. And if every possible value in the
> domain is a valid *input* (e.g. to `malloc`), then there is no way for
> the function to detect incorrect input at runtime.
This problem is why I proposed the status_value class.
> If it weren't for the STL's `size_type` snafu continually muddying the
> waters for new learners, I doubt people would be falling into the
> "unsigned for value range" antipattern anymore.
Well, I would, but I tend to use it to avoid ill-formed negative inputs.
> On Mar 12, 2018, Lawrence Crowl <Lawrence_at_[hidden]> wrote:
>> So the application intended modular arithmetic? I was concerned about
>> the normal case where 'unsigned' is used to constrain the value range,
>> not to get modular arithmetic.
>
> IMNSHO, if anyone is using unsigned types "to constrain the value range,"
> they are doing computers wrong. That is *not* what signed vs. unsigned
> types are for.
I note that size_t is unsigned to constrain the value range, not to obtain
modular arithmetic.
> As Lawrence himself wrote earlier in this thread:
>> If integer overflow is undefined behavior, then it is wrong. Tools can
>> detect wrong programs and report them.
>
> The contrapositive is: "If the programmer is using a type where integer
> overflow is well-defined to wrap, then we can assume that the program
> relies on that wrapping behavior (because there would otherwise be a
> strong incentive for the programmer to use a type that detects and
> reports unintended overflow)."
Yes. For the most part, programmers should be explicit when they want
anything other than mathematical integers.
> The original design for the STL contained the "unsigned for value range"
> antipattern. Consequently, they ran into trouble immediately: for
> example, `std::string::find
> <https://en.cppreference.com/w/cpp/string/basic_string/find>` returns an
> index into the string, naturally of type `std::string::size_type`. But
> size_type is unsigned! So instead of returning "negative 1" to indicate
> the "not found" case, they had to make it return `size_type(-1)`, a.k.a.
> `std::string::npos` -- which is a positive value! This means that
> callers have to write cumbersome things such as
>
> if (s.find('k') != std::string::npos)
>
> where it would be more natural to write
>
> if (s.find('k') >= 0)
I won't disagree with the easier syntax of the latter, but I note that
the function itself is returning two things: the search status, and iff
successful the index of the found object.
> This is sort of parallel to my quotation of Lawrence above: If every
> possible value in the domain of a given type is a valid output (e.g.
> from `find`), then there is no value left over with which the function
> can signal failure at runtime. And if every possible value in the
> domain is a valid *input* (e.g. to `malloc`), then there is no way for
> the function to detect incorrect input at runtime.
This problem is why I proposed the status_value class.
> If it weren't for the STL's `size_type` snafu continually muddying the
> waters for new learners, I doubt people would be falling into the
> "unsigned for value range" antipattern anymore.
Well, I would, but I tend to use it to avoid ill-formed negative inputs.
-- Lawrence Crowl
Received on 2018-03-13 01:22:14