Why does `checked_shr` only work with `u32`?

fn main() {
    let lhs = 50_u8;
    let rhs = 5_u8;
    
    lhs + rhs; // works
    lhs.checked_add(rhs); // works

    lhs >> rhs; // works
    lhs.checked_shr(rhs); // does not work, `rhs` needs `as u32`
}

What were the thoughts behind the design decision of not allowing checked_shr to work without casting to u32 ? For example checked_add on the other hand doesn't enforce u32 but instead works with the type it's called on.

The type of the right-hand-side of checked_shr is unrelated to the left-hand-side and is a u32 for all types. Shifting is fundamentally a different kind of operation than addition and using a u32 doesn't incur any loss of performance or loss of functionality.

Can you elaborate on why u32 is the perfect type for this and why making it the type operated on would not work?

The choice of u32 is arbitrary. Other types like u16 would probably work just as well.

However, it should be an unsigned type, because that's how the corresponding hardware instructions work. That means we can't just choose the same type for the left-hand-side and right-hand-side (because the LHS might be signed).

Note that in languages like C and C++, shifting by a negative number is undefined behavior. Rust prevents this at compile time by requiring an unsigned type on the RHS.

2 Likes

Just some extra un-needed info...

Your post made me wonder why u32 instead of u8 big enough. Or usize so in the future when we have huge ints it will be sure to be big enough?
Anyway digging around I see checked _shr was brought in by Alex Crichton back in 2015
commit 7eb76995933ee0ced03c23cdaeeeac86d7713450
to solve this issue...
https://github.com/rust-lang/rust/issues/27755

usize is probably a pointless change because I can't imagine why you'd ever want to shift by -- say -- 10 billion. Even u32 is overkill. I don't even think crypto would require you to do that (I may be wrong). Since bit shifting gives you a number with all bits except the one you shifted clear, and the number you shifted is the bit that's set, you'd need arbitrary-precision integers.

The real question is why the operators are implemented for all types, not why the methods are not.

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.