Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the Unsigned trait automatically give e.g. the One trait in Rust?

Tags:

types

rust

traits

I want to write generic functions of the form

fn my_function<T: num::Unsigned>(T: number) -> T

in order to use them for all unsigned integer types, so u8-u128. However, often I want to do something like

let n = number + 1;

or

let mut n = number;
number -= 1;

in the function body. Now, everytime I use something like that, Rust tells me that the std::ops::SubAssign-trait, the std::cmp::PartialOrd-trait, etc. is not implemented for T.

Is there an easy way to specify that my number is only one of the types u8-u128 and hence enjoys all of those traits? And why isn't this clear to the Rust compiler, i.e. what would be an example for an Unsigned-type that does not have the PartialOrd-trait?

Edit: To clarify: What I would love is a way to say "T has to have one of the types u8...u128 (and maybe BigUInt)" and then have Rust to automatically see "since T is of one of those types, the following traits have to be implemented for T: std::cmp::PartialOrd, std::ops::SubAssign, ..."

like image 364
Jakob E. Avatar asked Sep 15 '25 09:09

Jakob E.


1 Answers

On the contrary, T: Unsigned does imply T: One. Unsigned is a super trait over Num which is a super trait over Zero, One, and more:

pub trait Unsigned: Num { }
pub trait Num: Zero + One + NumOps<Self, Self> + PartialEq<Self> { ... }

The key thing to understand is that 1 is not the same thing as T::one(). This works for example:

use num::Unsigned; // 0.4.0

fn my_function<T: Unsigned>(number: T) -> T {
    number + T::one()
}

The NumOps trait means various arithmetic operators are defined, but only between Ts. The literal 1 may not be a T, T could be something like BigUint.


What I would love is a way to say "T has to have one of the types u8...u128 (and maybe BigUInt)" and then have Rust to automatically see "since T is of one of those types, the following traits have to be implemented for T: std::cmp::PartialOrd, std::ops::SubAssign, ..."

This is not how traits are designed to work. Traits can be implemented on foreign types, so even if Unsigned is only implemented for those types now, some other crate my implement it for their types which don't have all the same properties of u8...u128, etc.

Instead, you should constrain T to have the properties you need for the function to work. So you must be explicit.

like image 151
kmdreko Avatar answered Sep 17 '25 05:09

kmdreko