Modulo wraparound is just as much a feature in some situations as it is a bug in others. And signed vs unsigned are just different views on the same bag of bits (assuming two's complement numbers), most operations on two's complement numbers are 'sign agnostic' - I guess from a hardware designer's pov, that's the whole point :)
The question is rather: was it really a good idea to bake 'signedness' into the type system? ;)
That's why Rust has separate operations for wrapping and non-wrapping arithmetic. When wrapping matters (e.g. you're writing a hash function), you make it explicit you want wrapping. Otherwise arithmetic can check for overflow (and does by default in debug builds).
> Modulo wraparound is just as much a feature in some situations as it is a bug in others.
That’s an extremely disingenuous line of reasoning, the situations where it’s a feature is a microscopic fraction of total code: most code is neither interested in nor built to handle modular arithmetics, and most of the code which is interested in modular arithmetics needs custom modulos (e.g. hashmaps), in which case register-size-modulo is useless.
That leaves a few cryptographic routines built specifically to leverage hardware modular arithmetics, which could trivially be opted in, because the developers of those specific routines know very well what they want.
> signed vs unsigned are just different views on the same bag of bits […] The question is rather: was it really a good idea to bake 'signedness' into the type system? ;)
The entire point of a type system is to interpret bytes in different ways, so that’s no different from asking whether it’s really a good idea to have a type system.
As to your final question, Java removed signedness from the type system (by making everything signed). It’s a pain in the ass.
> Java removed signedness from the type system (by making everything signed)
That's not removing signedness. Removing signedness would be treating integers as sign-less "bags of bits", and just map a signed or unsigned 'view' over those bits when actually needed (for instance when converting to a human-readable string). Essentially Schroedinger's Cat integers.
There'd need to be a handful 'signed operations' (for instance widening with sign extension vs filling with zero bits, or arithmetic vs logic right-shift), but most operations would be "sign-agnostic". It would be a more explicit way of doing integer math, closer to assembly, but it would also be a lot less confusing.
Modulo wraparound is convenient in non-trivial expressions involving addition, subtraction and multiplication because it will always give a correct in-range result if one exists. "Checking for overflow" in such cases is necessarily more complex than a simple check per operation; it must be designed case by case.
The question is rather: was it really a good idea to bake 'signedness' into the type system? ;)