10 ms·
things are still a bit messy with integer overflow No, they aren't messy, they're fully defined. Integer overflow in safe Rust works just like Java: the numbe
by crotchfire 3y ago
things are still a bit messy with integer overflow
No, they aren't messy, they're fully defined. Integer overflow in safe Rust works just like Java: the numbers wrap around. It's totally defined.
You can, optionally, also enable a runtime check for this wraparound. This is usually enabled for debug builds. There is of course a performance cost to doing this.
- vlovich123 3y agoI didn't say they're undefined but I guess we can agree to disagree that integer addition behavior depending on debug vs release is messy.
- throwaway81523 3y ago> they aren't messy, they're fully defined. Integer overflow in safe Rust works just like Java: the numbers wrap around. That is both fully defined and messy. They are not mutually exclusive. It means there are integers where n+1 is less than n. That is messy. No integers that I learned about in math class work like that. The only two non-messy well-defined behaviours are 1) bignums by default like in Python, but not suitable for a low level language like Rust; or, 2) trap on overflow, like Ada is supposed to do though it is usually shut off by a pragma. Both of those have significant runtime cost.
- mike_hock 3y ago> No integers that I learned about in math class work like that. Did you learn about modular arithmetic in math class? > The only two non-messy well-defined behaviours are 1) bignums by default like in Python, but not suitable for a low level language like Rust; or, 2) trap on overflow, like Ada is supposed to do though it is usually shut off by a pragma. Both of those have significant runtime cost. No, they're not the only "non-messy" behaviors. An example of where wraparound is the desired behavior is computing hash functions. An example of where saturating arithmetic is the desired behavior is processing audio samples.
- throwaway81523 3y ago> Did you learn about modular arithmetic in math class? I knew some wiseacre would say that. No those aren't integers, they are equivalence classes of integers. Yes there are times when wraparound is desirable, just like there are when addition mod 12 is desirable (when figuring out times of day). But you don't want the default behaviour of integers to give 8+5=1. If you want that, fine, but ask for it explicitly. For example, in Ada, if you want modular arithmetic, just specify it in the variable declaration. That is the right way to do it. C++ gets it wrong in that unsigned overflow is modular, signed overflow is UB (so at least you can ask the compiler to signal an exception), but there is no option of unsigned arithmetic where overflow is an exception.
- mike_hock 3y ago> those aren't integers, they are equivalence classes of integers. And they form a ring and sometimes even a field. That's the least messy behavior of any arithmetic type usually implemented on a computer. The only messy part is division, which doesn't match modular division, but it's what you actually want, usually. Most of the design problems around arithmetic types in programming languages are a result of people "wanting integers" (or "real numbers") rather than facing the reality of the machines they're programming for. > trap on overflow, like Ada is supposed to do though it is usually shut off by a pragma Sounds like people "usually" opt for "messy" behavior. > For example, in Ada, if you want modular arithmetic, just specify it in the variable declaration. That is the right way to do it. No disagreement there. Unfortunately, almost all non-niche programming languages get arithmetic wrong, ironically, because they're supposed to be the simplest types. You have to choose from a range of possible behaviors that all have their use cases, and you have to be aware of the limitations of the actual type you're working with, which is not an integer but something finite. The language cannot make that choice for use. What the default is almost doesn't matter because choosing a particular behavior should be clear and simple.
- throwaway81523 3y agoIt sounds like you're telling me Rust also gets it wrong. C and C++ at least allow the implementation to do the right thing (i.e. trap) on overflow for signed ints, though they mandate doing the wrong thing for unsigned. I'd call Rust, Ada, C, and C++ all niche languages these days though (the niche is low level system work). #1 on TIOBE is Python whose native arithmetic type is arbitrary precision, which is really the right thing to do. Yes, modular arithmetic is convenient for computers, but it's not integer arithmetic! If you're using machine words to denote actual integers, and your program does something that causes an overflow, that is an error and signalling the error is far better than quietly giving the wrong answer. It's just like in Python where ints are arbitrary precision. They can still get too big for the implementation (i.e. the computer can run out of memory) but that is unquestionably an error condition. Machine integers are the same thing except the constraint is running out of bits in the machine word, rather than running out of memory. If that happens, it's also an error, unless you chose a datatype indicating a different intention. This all seems obvious to me, but I've seen the same misunderstanding in other places before. I don't understand why it isn't obvious to everyone.