A concept-centered standard library for C++20, enabling safer and more reliable products and a more modern feel for C++ code.; Also home of Subdoc the code-documentation generator.
Rust shift operators take a rhs value of u32, which we emulated, however this introduces a sharp edge in C++ where you shift by something like a sizeof() expression. That evaluates to a size_t which used to implicitly narrow to unsigned in order to shift. But with safer types there is no implicit narrowing and you need to write
u32::try_from(shift).unwrap()
Which is then fed to the shift operator which will check (again) that the shift amount is in range.
Nowhere near the full range of values of u32 is in range for a shift operation, so the size of the type is somewhat arbitrary. So the value inside must be checked regardless.
By allowing u64/usize types to be used on the rhs of the shift, we avoid having to write conversions where they aren't holding weight.
This makes the C++ operators accept things that the Rust operators do
not. Why is C++ different here?
The answer here is that
1) casting in rust is much simpler, a sizeof<T>() as u32 expression is
simpler than the noise introduced by conversions in C++ like
sus::cast<u23>(sizeof(T))
2) we need to rewrite a lot of code that already assumes it's fine to
shift by a size_t
3) Rust type deduction allows Rust code to avoid naming the type of
things at all and it can pick a u32, whereas C++ will need to pick a
type and it will often have picked a size_t/usize.
What mitigates this difference?
And the extra expressivity does not allow C++ to do different things or change expectations wrt the behaviour of the shift operators.
Rust shift operators take a rhs value of u32, which we emulated, however this introduces a sharp edge in C++ where you shift by something like a
sizeof()
expression. That evaluates to asize_t
which used to implicitly narrow to unsigned in order to shift. But with safer types there is no implicit narrowing and you need to writeu32::try_from(shift).unwrap()
Which is then fed to the shift operator which will check (again) that the shift amount is in range.
Nowhere near the full range of values of
u32
is in range for a shift operation, so the size of the type is somewhat arbitrary. So the value inside must be checked regardless.By allowing u64/usize types to be used on the rhs of the shift, we avoid having to write conversions where they aren't holding weight.
The answer here is that 1) casting in rust is much simpler, a
sizeof<T>() as u32
expression is simpler than the noise introduced by conversions in C++ likesus::cast<u23>(sizeof(T))
2) we need to rewrite a lot of code that already assumes it's fine to shift by a size_t 3) Rust type deduction allows Rust code to avoid naming the type of things at all and it can pick a u32, whereas C++ will need to pick a type and it will often have picked a size_t/usize.And the extra expressivity does not allow C++ to do different things or change expectations wrt the behaviour of the shift operators.