Question: why does dividing by zero have no safety guarantee's?

Hello, as far as i understand when there's a possibility of a runtime crash rust tries to have explicit crash language like .unwrap() and pattern matching to deal continue running. Why is this not true for divide? divide can divide by 0 crashing at runtime. I expected that rust might have required unwrap for this or some other handling. consider:

fn main() {
  let mut a = 10;
  loop {
    a -= 1;
    dbg!(5/ a);
  }
}

this results in

    Blocking waiting for file lock on build directory
   Compiling my-project v0.1.0 (/home/runner/HorizontalEnchantingSphere)
    Finished dev [unoptimized + debuginfo] target(s) in 1.11s
     Running `target/debug/my-project`
[src/main.rs:5] 5 / a = 0
[src/main.rs:5] 5 / a = 0
[src/main.rs:5] 5 / a = 0
[src/main.rs:5] 5 / a = 0
[src/main.rs:5] 5 / a = 1
[src/main.rs:5] 5 / a = 1
[src/main.rs:5] 5 / a = 1
[src/main.rs:5] 5 / a = 2
[src/main.rs:5] 5 / a = 5
thread 'main' panicked at 'attempt to divide by zero', src/main.rs:5:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
exit status 101

A possible solution would be for divide to always return an Option<T> but that might be annoying. Thoughts?

There is checked_div already. In fact, there's a whole family of checked/wrapping/saturating arithmetic functions.

3 Likes

I see. Thats very interesting, I guess i thought that this would be compiler enforced and not optinal.

When it comes to basic arithmetic, Rust chose performance and convenience over strict correctness, so, for example, addition does not return a Result even though it's a partial function (it may overflow). And it doesn't even panic by default in release mode but wraps around instead (so directly maps to hardware addition). Rather there are named methods for different ways to handle overflow. The same goes for division by zero.

2 Likes

If you #![warn(clippy::integer_arithmetic)] in your toplevel lib.rs, clippy will tell you about all of the places in your arithmetic that have overflow/underflow/panic potential, which is good when you need high confidence in your arithmetic like cryptography

5 Likes

It does have a safety guarantee: The program will definitely panic when you try to divide by 0.

16 Likes

If the division returned Result, 99% of the time users would .unwrap() it. Hence, it is more convenient to provide functionality that does it for you, and leave checked_div for those special 1% scenarios.

Similarly, indexing an array will panic when the index is out of range because 99% of the time the index is known to be correct, and you have get for those special scenarios where it isn't.

Also note that "safety" has a special meaning in Rust. Panicking is a safe operation in Rust lingo.

5 Likes

A question is what "crashing" means in this matter. Regarding "safety", it is guaranteed that any non-unsafe operation does not cause undefined behavior (UB), i.e. there will either be a "clean" panic or some other sort of error or wrongly computed result, but not a "crash" as in "anything could happen".

Integer overflows are not guaranteed to panic (they can return wrong results, but not cause UB).

Example:

fn main() {
    let mut height: i32 = "2147483640".parse().unwrap();
    height += 10;
    if height < 1 {
        println!("Disable thrusters.");
    }
}

(Playground in --release mode)

Integer division by zero is guaranteed to panic in Rust (see also this recent issue regarding the reference), while integer division in C is undefined behavior (UB) (see also this stackoverflow post).

Similar for overflows: Overflowing a signed number in C is UB (which was very surprising to me when I learned about it), whereas in Rust an integer overflow will either cause a wrong result (as in the Playground link above) or a panic (when compiling in debug mode, which is default when you execute cargo run).

So Rust has some sort of "safety guarantees" both in regard to integer overflow and integer division. If you need more, you can use checked_div, as pointed out above.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.