Skip to content

Numeric traits inconsistent with integer type system #21069

Closed
@sneves

Description

@sneves

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.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions