3 ms·
This says again that the right behaviour for int overflow should be to trap, rather than wrap around or go into the weeds with UB.
by throwaway81523 4y ago
This says again that the right behaviour for int overflow should be to trap, rather than wrap around or go into the weeds with UB.
- nextaccountic 4y agoI think the Rust approach of having different methods for wrapping and checked addition is excellent. If you have two i32, x.wrapping_add(y) [0] is a sum where you have wrapping semantics. x.saturating_add(y) [1] is a saturating sum (when it reaches the max it stays there instead of overflowing), nd x.checked_add(y) [2] is a sum that catches overflow. If you are doing wrapping arithmetic a lot, there's a convenience wrapper (heh), Wrapping [3], so that if x and y have type Wrapping<i32>, then x + y always wraps (like calling wrapping_add on two i32). There's a Saturating<i32> too but it's nightly-only for now. The only downside of Rust's approach is that if you have x + y on two plain integers, the language itself doesn't specify whether it will panic (and interrupt the execution of the program) or not. By default, debug builds will panic and release builds wraps (on the understanding that unintended overflows are always a bug, but catching this bug on release builds has some performance penalty, so it isn't caught by default on release), but you can control this by setting overflow-checks = true on the release profile on Cargo.toml [3] I think future versions of Rust should set overflow-checks = true by default even on release builds, but right now it's only a matter of adding a single line on Cargo.toml to enable it, and almost every program should do it. With this on, x + y will panic on overflow if they are i32, will wrap if they are Wrapping<i32> and will saturate if they are Saturating<i32> [0] https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_add https://doc.rust-lang.org/std/primitive.i32.html#method.wrap... [1] https://doc.rust-lang.org/std/primitive.i32.html#method.saturating_add https://doc.rust-lang.org/std/primitive.i32.html#method.satu... [2] https://doc.rust-lang.org/std/primitive.i32.html#method.checked_add https://doc.rust-lang.org/std/primitive.i32.html#method.chec... [3] https://doc.rust-lang.org/stable/std/num/struct.Wrapping.html https://doc.rust-lang.org/stable/std/num/struct.Wrapping.htm... [4] https://doc.rust-lang.org/cargo/reference/profiles.html#overflow-checks https://doc.rust-lang.org/cargo/reference/profiles.html#over...
- brundolf 4y agoIt's off by default in production because all those overflow checks add up (hah). Rust's first priority has always been low-level/systems code, where these things matter. It (semi-controversially) makes runtime bounds checks despite that priority, because they're so important to memory safety, but with that guard-rail numeric overflows become less important- they can only cause logic bugs, not safety issues, so it makes sense to me that performance would then be prioritized by default
- stouset 4y agoAlso, thanks to the language, most bounds checks can be elided in practice with idiomatic code. This isn’t as often the case with arithmetic operations. I do wish there was a(n optional) clippy lint to warn against non-explicit integer arithmetic operations though.
- twic 4y agoWhat do they add up to? You can turn overflow checks on in release mode with -C overflow-checks=on, so it feels like it should be really easy to benchmark the current impact. I couldn't find any benchmarks doing this, though.
- brundolf 4y agoI'm sure it varies wildly by the type of program, and I'm sure much smarter people than me on the Rust team did their benchmarking homework when they originally made the choice. Just saying that to me, it seems like a reasonable default
- throwaway81523 4y agoIt seems like a seriously wrong default for a language whose story is supposed to be safety. People wanting unsafe languages already have C and C++ for that :/.
- 4y ago
- jeroenhd 4y agoI agree from a language standpoint but trapping overflows by default would be quite costly. If you get the branch predictor involved with every addition or multiplication then you'll very quickly slow down your program, especially in the hot code paths. I think most general purpose programs don't run into overflow anymore these days, and the performance benefit probably outweighs the safety for most people.
- cerved 4y agoI think the opposite is true, most software projects benefit from safety and not performance
- throwaway81523 4y agoMost programs should be written in HLL's with unbounded integers and garbage collection. There are a few programs that need machine arithmetic and manual memory management, for performance or whatever reasons, and Rust is intended to allow writing those programs safely. So it seems like a mistake to not treat int overflow as a serious error. Idk if branch prediction or whatever would have to be involved. Most architectures will already trap on divide by zero or things like that, and will set a condition code for int overflow. Making the condition code sticky like it is for IEEE floating point arithmetic would allow doing a software trap once a basic block finished. It is a shame that the current trendy architecture (Risc-V) goes the opposite way and has no condition codes at all.
- mayoff 4y agoSwift does this. Bare operators like + and * trap (crash) on overflow. You can use &+ and &* for 2s complement wrapping.