Loop counters really are not the problem. The problem is that even when using unsigned integers you often want to do 'signed math' on them (e.g. adding a negative amount, or you could have an expression made entirely of unsigned integers (like ((x - y) + z) where an intermediate result may become negative even when the end result is positive - and in languages with overflow check that may result in a panic).

A better rule of thumb is to always use signed integers, except for bit twiddling and modulo-math.

Especially with 64-bit integers it's really no longer an issue to lose one bit for the sign (63 bits ought to be enough for anybody heh).

But are we necessarily limited to native integer types? At least with C++, the type system is powerful enough to support integer replacement types (eg. [0][1]) that don't inherit these issues. (Where, for example, the subtraction of an unsigned from another unsigned returns a value of signed integer type.) Another advantage being the ability to customize the overflow/underflow handling policy per declaration (rather than relying on a compiler flag that applies globally).

[0] https://www.boost.org/doc/libs/develop/libs/safe_numerics/do...

[1] https://github.com/duneroadrunner/SaferCPlusPlus/blob/master...

I would rather do away with signed vs unsigned integer types completely, and instead have sign-agnostic integers like down on the assembly level (the world has settled on two's-complement anyway). Signed-vs-unsigned only matters in one situation: when extending a narrow integer type to a wider integer type (e.g. "sign-extension"), and this could be an explicit operation.

Beyond that, the decision whether a number is signed or unsigned is only needed for string formatting (e.g. it's like Schroedingers integers: whether a number is signed or unsigned only matters when you actually look at the number).

Wait till this guy learns about multiplication and division

Yeah ok got me, but AFAIK at least multiplication is sign-agnostic when the result is clamped to the width of the inputs (e.g. the result of multiplying two 64-bit values being clamped to 64-bits). Not sure about division though.

But in any case: with 'sign-agnostic' integer types high level languages would simply need separate signed vs unsigned mul/div operators. Not a big thing when modern languages already have different operators for wraparound vs overflow-checked arithmetic (for instance + vs +% in Zig).

[deleted]