13
halfflat
129d

Unsigned type means mod 2^n. It's not rocket science, argh!

Context: colleagues surprised by/demand comments for code like: static constexpr unsigned max_value = -1;

Recommended alternative: static constexpr unsigned max_value = std::numeric_limits<unsigned>::max();

Which will work great until someone carelessly increases the width of max_value to size_t or somesuch.

Comments
  • 2
    Why have a constant in the first place when you have that function that will give you max for any type? Maybe the point is to shorten the length, but you can't blame them if it gets changed - max_value is an ambiguous name, use something like uint32_max.

    Anyways, I would prefer the latter over the former because it is more clear about what you're doing - the point of code is to be readable, not concise.
  • 0
    Also, welcome to devRant!
  • 2
    @tokumei 'max_value' was just a stand-in, but the point is that -1 is succinct and works for any unsigned type. Using numeric_limits is verbose, dangerous if only one of the types is changed, and completely unnecessary if people would just understand that unsigned types are mod 2^n.

    It's basically what the unsigned types _mean_ in C and C++. And it's why unsigned arithmetic is so much more easy to reason about than signed.
  • 1
    @jallman112 Thanks! So many rants, so little time.
  • 0
    Code shouldn't need comments it should explain itself.

    Besides... You're gonna ask the person that made unreadable code to explain his code in readable comments? :)
  • 1
    I've been using -1 for that since high school. There are seriously instructors that demand comments explaining it?

    ... Well of course there are. People are stupid. 😡
  • 0
    No, it goes against everything they think unsigned types are, and it can be confusing if they don't immediately recall that integers can overflow in C. It's the same reason why you _should_ document fields that intentionally overflow (and why Rust chooses to panic in debug mode if that happens and you don't specifically use the `overflowing_add` method.

    It's a logic error that needs to be caught when unexpected and a feature that needs to be properly noted when used.
  • 0
    @tokumei Then they are wrong about what unsigned types are and any code they touch which uses them is in danger.
  • 0
    @tokumei And the thing is, integers *can't* overflow in C++. Unsigned integers wrap, and it's undefined behaviour for signed integers.
  • 0
    @halfflat What I mean is that the operation overflows - what is happening on most CPU architectures is that the OVERFLOW flag was set. When an operation overflows, of course the result is typically left wrapped to avoid any expensive checks. C/C++/most languages strongly based on them ignore that bit and assume it's an expected behavior.

    Integers of a certain size obviously can't "overflow" and have a value bigger than their size can hold; that's absurd.

    Same thing happens for signed types, at least if they're stored in two's complement; the reason why it's said to be undefined behavior is that they may be implemented in a different way.
  • 1
    @tokumei I think we might be talking at cross purposes. There is a certain prescribed set of semantics for arithmetic on integral types in the specification of the language. This is one step removed from the implementation of that behaviour, noting of course that these semantics were chosen so as to admit efficient execution.

    As per this specification, unsigned arithmetic is exactly modulo 2^n, and signed arithmetic has undefined behaviour on overflow, a fact which is indeed exploited by compilers, for example, to assert that an expression like (x+1>x) is always true if x is of type int.

    By virtue of this specified behaviour, -1 is a negative int value, which gets converted to the smallest unsigned value which is equal modulo 2^n. It's not an accident or artifact of the generated assembly; it is *just what it means* as C++ code.

    It is crucial to understand these very basic types. Otherwise you get code like:

    for (auto i=0; i<x.size(); ++i) { ... }

    (topic for another rant).
Your Job Suck?
Get a Better Job
Add Comment