3 ms·
This deserves elaborating on, because it's pretty cool. Rust has two behaviours around overflow. In debug builds, it panics, in release builds it wraps. IMO w
by pdpi 2mo ago
This deserves elaborating on, because it's pretty cool.
Rust has two behaviours around overflow. In debug builds, it panics, in release builds it wraps.
IMO wrapping is a reasonable-enough behaviour to avoid UB in release builds, and panicking in debug is definitely the correct behaviour, because you're only avoiding UB by defaulting to something, but that's not nearly enough. In most applications where overflow is a risk you should make sure to choose what behaviour you consider correct.
Thankfully Rust has a pretty robust story around this:
fn add_behaviour() {
let small: i32 = 123;
let big: i32 = i32::MAX;
assert_eq!(small.wrapping_add(big), i32::MIN + 122);
assert_eq!(small.overflowing_add(big), (i32::MIN + 122, true));
assert_eq!(small.overflowing_add(small), (246, false));
assert_eq!(small.saturating_add(big), i32::MAX);
assert_panics!(a.strict_add(b)); // (nb: Not a real assertion)
}
And you could easily implement the default behaviour yourself with conditional compilation:
impl Add for u32 {
type Output = u32;
fn add(self, rhs: u32) -> u32 {
#[cfg(debug_assertions)]
{
self.strict_add(rhs)
}
#[cfg(not(debug_assertions))]
{
self.wrapping_add(rhs)
}
}
}