Why does Rust not provide an Integer trait?

Rust's integer types: u8, u16, u32, usize, u64 and their signed counterpart, have a lot of similar methods and trait, such as from_be_bytes, From<u8> and TryFrom<u64>, and I believe they are implemented by macros in source code.

However, I find it difficult to be generic over integer types. I know num crate has Integer trait, but it only provides a little functionalities. So if I want to use most of the integer's common methods, I should use macros by example to write my code instead of generic traits.

I really wonder why it is designed like this, since trait is obviously fit for this situation.

I wasn't privy to the discussions made back when Rust hit 1.0, but I'm guessing the big reason is it's hard to know what should and shouldn't be in such a Integer trait.

For your curiosity, you may want to see what the impl_int!() macro generates. It's something like 2000 lines of methods, and imagine copy/pasting that to implement the Integer trait for all the integer types supported by Rust.

I'm curious how much benefit an Integer trait really provides.

The integer types share methods, but how often do you really want to be able to generically substitute arbitrary size integers without worrying about overflows or signed behavior?

Rarely, if ever, in code do I find myself thinking: "The client could use a u8 or an i128 here and I don't care."

1 Like

It's useful for functions that are more mathematical. Currently we have to use a macro to generate them, which doesn't always play too well with tooling. However, rust-analyzer has become much better at handling macros so it's less of an issue than it used to be. Incidentally, I do tend to draw a stronger distinction between signed and unsigned integers. I've often found they need to be handled differently.

Though ultimately the benefit (or lack thereof) of more generic integer types is going to strongly depend on what type of work you do. I'd guess that there hasn't yet been a strong push for a more ergonomic solution because the use case is quite niche and the workarounds work well enough.

1 Like

The history of the design choices can be found here RFC 319 discussing the stabilization for the std::num module.

In general, if you are interested in "how did I get here?", the RFC book is a great place to go.


But from the RFC issue, it seems that this RFC is closed because "This has been implemented for some time now".

In this RFC, std::num module should contain Int, Signed and Float trait. But current version doesn't have those. It is still unknown to me why this trait is removed.

The std::num traits were moved to the num crate before Rust 1.0 was released. This was done for several parts of the standard library, because shipping something in the standard library means committing to supporting it forever, while external crates have more flexibility to evolve and improve their design.