Division of NonZero<usize>

I am playing around with std::num::NonZero in a crate of mine.

use std::num::NonZero;

fn main() {
    let four = NonZero::new(4).unwrap();
    let two = NonZero::new(2).unwrap();
    let div = four / two;
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0369]: cannot divide `NonZero<{integer}>` by `NonZero<{integer}>`
   --> src/main.rs:6:20
    |
6   |     let div = four / two;
    |               ---- ^ --- NonZero<{integer}>
    |               |
    |               NonZero<{integer}>
    |
note: the foreign item type `NonZero<{integer}>` doesn't implement `Div<NonZero<{integer}>>`
   --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/num/nonzero.rs:115:1
    |
115 | pub struct NonZero<T: ZeroablePrimitive>(T::NonZeroInner);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not implement `Div<NonZero<{integer}>>`

For more information about this error, try `rustc --explain E0369`.
error: could not compile `playground` (bin "playground") due to 1 previous error

Why is dividing NonZero not implemented?

At a guess, because the result can't be NonZero<_> unless it panics on cases like NonZero(2) / NonZero(4).

3 Likes

That was my first thought too. Would that mean that checked_div could theoretically be implemented returning None when a 0 is produced?

2 Likes

Indeed. Hence I'd expect Output to be T, not NonZero<T>.

1 Like

I see thereโ€™s a trait implementation for unsigned types, like u๐‘ / NonZero<u๐‘> with result u๐‘, so impl Div<NonZero<u๐‘>> for u๐‘ { type Output = u๐‘; โ€ฆ }. The rationale for providing this impl is probably that for those, the division can avoid overflow-checks, so using this impl improves efficiency.

For unsigned types u๐‘ (u8, u16, etcโ€ฆ) and two variables, both NonZero<u๐‘> like x: NonZero<u๐‘>; y: NonZero<u๐‘>, you can thus do division with x.get() / y, converting just the left-hand-side, and still benefiting from this more efficient implementation.

For signed types i๐‘ (i8, i16, etcโ€ฆ) however, thereโ€™s another overflow case: i๐‘::MIN / -1. Since overflow is possible anyway, itโ€™s probably expected that you might as well just use i๐‘ values from the beginning; e.g. x.get() / y.get().

8 Likes

I just realized, that my original example was not clear enough. I'm actually using usize, not i32:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.