From all the integer traits present in std::num, only SignedInt includes Neg. The Neg trait is not implemented by Int and UnsignedInt types because, presumably, it does not make sense to negate unsigned integers. I will not argue whether this is a good policy or not.
However, this makes writing generic code for unsigned types harder than it needs to be. For example, suppose we have the function
fn f(x: u32) -> u32 { -(x >> 31) }
This function works perfectly (albeit with a warning, but it is valid Rust as far as I can tell) when implemented with a concrete unsigned integer type. However, when making the function generic it stops working:
fn f<T: UnsignedInt>(x: T) -> T { -(x >> (size_of::<T>()*8 - 1)) }
// error: cannot apply unary operator `-` to type `T`
Changing this to 0 - <expression> is a simple solution, but one that also does not work very well without pulling other (NumCast, FromPrimitive) traits. Another solution is to pull in the Neg trait directly, but this increases verbosity due to Neg's associated type machinery. All in all, the lack of unsigned negation complicates things.
Now, I accept that you may not want to make unsigned negation common or encouraged behavior. But in that case it also makes no sense to have the - operator available at all for unsigned types; users that really want such semantics can replace it by 0-<expression> in non-generic code.
My overall point is:
- If
u32, usize, etc allow negation, i.e., have the Neg type implemented, so should UnsignedInt;
- If
UnsignedInt is not meant to be negatable, neither should be u32, usize, etc.
From all the integer traits present in
std::num, onlySignedIntincludesNeg. TheNegtrait is not implemented byIntandUnsignedInttypes because, presumably, it does not make sense to negate unsigned integers. I will not argue whether this is a good policy or not.However, this makes writing generic code for unsigned types harder than it needs to be. For example, suppose we have the function
This function works perfectly (albeit with a warning, but it is valid Rust as far as I can tell) when implemented with a concrete unsigned integer type. However, when making the function generic it stops working:
Changing this to
0 - <expression>is a simple solution, but one that also does not work very well without pulling other (NumCast,FromPrimitive) traits. Another solution is to pull in theNegtrait directly, but this increases verbosity due toNeg's associated type machinery. All in all, the lack of unsigned negation complicates things.Now, I accept that you may not want to make unsigned negation common or encouraged behavior. But in that case it also makes no sense to have the
-operator available at all for unsigned types; users that really want such semantics can replace it by0-<expression>in non-generic code.My overall point is:
u32,usize, etc allow negation, i.e., have theNegtype implemented, so shouldUnsignedInt;UnsignedIntis not meant to be negatable, neither should beu32,usize, etc.