I am a beginner in Rust and currently implement my own fixed-point arithemtic.
While implementing bitshift operations I noticed something that bugs me.
let a:i32 = 100;
let b = 3;
let c:i32 = a << b;
Why does bhave to be i32 as well?
It makes no sense in my head that you can bitshift with a potentially negative value (I come form a C-like language). I would have thought that Rust tries to force me to use an unsigned type here to enforce more code safety. Maybe even just u8 as there is no primitive type that makes sense to apply bitshifts of more than 63.
It doesn't have to be. Shl is implemented for every combination of integer lhs and rhs. The type checker just defaults the rhs type to the lhs type. If you explicitly specify a type for b, then it will use that type just fine.
Note that because this trait is implemented for all integer types with multiple right-hand-side types, Rust's type checker has special handling for _ << _ , setting the result type for integer operations to the type of the left-hand-side operand.
In C shifting by an amount that is equal or greater than the bitsize of the lhs is UB. In Rust this can't be true. Thus in debug mode you get a panic and in release mode the rhs is masked such that the UB can't happen.
We have u128 and i128.
Even limiting to u8 would not be enough, as you could still have values bigger than the maximum sensible shift amount.
Note that the Shl trait, std::ops::Shl, can be applied to more than machine-level integers. The second example in the documentation of the trait spins a vector leftward by a given amount. That vector could have up to isize::MAX entries, a value much larger than u8::MAX.