# Please can we add a basic num trait?

**URL:** <https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449>\
**Category:** libs\
**Created:** [April 10, 2022, 3:51pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449 "2022-04-10T15:51:58Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 10, 2022, 3:51pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/1 "2022-04-10T15:51:58Z")

</div>

There's a great debate on a shopping list of things we don't have:

> [@What numeric traits make sense for std?](https://internals.rust-lang.org/t/what-numeric-traits-make-sense-for-std/10814):
>
> For a second, pretend we have GAT, Const Generics, and whatever your favorite type system feature is. What numeric traits would make sense to have in std? What numeric traits would make sense to not have in std, but in a "2nd party" (i.e. officially endorced) crate? What numeric traits might be useful but can be relegated to a 3rd party crate? I'm not really concerned with how the traits would be laid out. I'm interested in what functionality you think deserves to be standardized vocabulary fo…

Unless you're pulling in the num-traits crate, life is still pretty unpleasant if you want to do anything generic across all the integer types that rust has. There are hacks to get everything you need but it's ugly and not anything that you would want to show to a beginner. Is there any reason why we can't add a `NumInfo` trait to give the basics of MAX, MIN, BITS, is\_signed(), ZERO, ONE?

Computers are generally used to process numbers and strings so it's helpful to adoption if we can do both of these out of the box without needing external crates.

People say that one and zero are not necessary for std lib but we want people to read rust code and understand it and having zero and one being explicit would make code more readable and simpler to understand.

(If there's a related PR/Issue that I missed please point me at it)

To me this feels like we just have not got round to joining the dots. This feels fairly uncontroversial (waiting to be disabused of this notion!) so I thought I would ask here and find out if there's any reason not to raise a PR so we can see how it feels in nightly...

---

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 10, 2022, 4:02pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/2 "2022-04-10T16:02:45Z")

</div>

As well as this being useful for people building on rust, this would enable tidying up some of the code in the std lib itself around number handling.

---

<div class="post-metadata">

**Author:** ![zackw](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/zackw/32/2071_2.png) [@zackw](https://internals.rust-lang.org/u/zackw)\
**Post date:** [April 10, 2022, 5:01pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/3 "2022-04-10T17:01:18Z")

</div>

I want this too, but it sounds like there are some serious practical obstacles, e.g. [from the previous thread](https://internals.rust-lang.org/t/what-numeric-traits-make-sense-for-std/10814/8):

> Mind that moving traits to std makes it impossible to add a new required item. `Float` , `Real` , and `PrimInt` contain dozens of required items and it seems likely that we'd want to add new methods in the future.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 10, 2022, 5:31pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/4 "2022-04-10T17:31:49Z")

</div>

We could seal them, at least for now if not indefinitely.

There are two separate goals here: having a trait to abstract over the integer types, and having a trait to add new integer types. Solving the former is much easier.

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [April 10, 2022, 7:52pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/5 "2022-04-10T19:52:01Z")

</div>

As a possible point of discussion, here is a trait that I wrote in one of my own projects to abstract over the primitive integer types…

```rust
pub trait Integer:
  'static
  + num::PrimInt
  + num::Integer
  + num::FromPrimitive
  + num::bigint::ToBigInt
  + AddAssign<Self>
  + SubAssign<Self>
  + MulAssign<Self>
  + WrappingAdd
  + WrappingSub
  + WrappingMul
  + for<'a> Add<&'a Self, Output = Self>
  + for<'a> Sub<&'a Self, Output = Self>
  + for<'a> Mul<&'a Self, Output = Self>
  + CheckedShl
  + CheckedShr
  + Shl<u32, Output = Self>
  + Shr<u32, Output = Self>
  + ShlAssign<u32>
  + ShrAssign<u32>
  + std::iter::Sum
  + Debug
  + Display
  + Default
  + Send
  + Sync
{
  fn saturating_mul(self, other: Self) -> Self;
  fn total_bits() -> u32 {
    mem::size_of::<Self>() as u32 * 8
  }
  fn nonsign_bits() -> u32;
  fn to_big_rational(&self) -> BigRational {
    BigRational::from(self.to_bigint().unwrap())
  }
  fn squared(self) -> Self {
    self * self
  }
}

```

Obviously, the collection of stuff I dumped in there is pretty ad-hoc, but it would definitely be _nice_ if I didn't have to write down all that stuff to make the other parts of my code be more convenient. And it doesn't even have everything I'd like it to (since you can't express `&'a Self: for<'a> Add<&'a Self, Output = Self>` as a supertrait, can't write numeric literals with them, etc.)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 10, 2022, 8:17pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/6 "2022-04-10T20:17:35Z")

</div>

> [@gilescope](#):
>
> Unless you're pulling in the num-traits crate, life is still pretty unpleasant

Is it still unpleasant if you _are_ pulling in the num-traits crate? Being able to release new major versions _because_ it's a crate seems like a huge advantage of it being in a crate, vs std.

If we want to be able to add more things to the trait ever, then I agree it'd have to be sealed in `core`, which means it's not an extensibility point any more, and thus you still need something like `num-traits` for all the library code that wants to be able to be generic over custom numeric types too. (For example, `uom` types as just came up in [Working around the orphan rule - help - The Rust Programming Language Forum](https://users.rust-lang.org/t/working-around-the-orphan-rule/73970?u=scottmcm) )

> [@gilescope](#):
>
> to give the basics of

I think the core problem here is that what exactly the basics _are_ isn't that obvious.

For example, `NonZeroU32` clearly shouldn't have `ZERO`. But [`MAX`](https://doc.rust-lang.org/nightly/std/num/struct.NonZeroU32.html#associatedconstant.MAX), [`MIN`](https://doc.rust-lang.org/nightly/std/num/struct.NonZeroU32.html#associatedconstant.MIN), [`BITS`](https://doc.rust-lang.org/nightly/std/num/struct.NonZeroU32.html#associatedconstant.BITS), `ONE` are all completely plausible for it, so it'd seem a shame to me to say that it's not `NumInfo` despite being in `std::num`.

Or how exactly should these be represented? Your list, for example, suggests that `is_signed` is a method, unlike the others that are all constants. Why is that? Why not `IS_SIGNED` or a separate trait?

There are also completely different approaches, like the one I experiment with in [zero-one — Rust library // Lib.rs](https://lib.rs/crates/zero-one), where instead of a `Zero` _trait_ there's a `Zero` _type_ (which is zero-sized), and instead of `T::zero()` one uses `T::from(Zero)` or `Zero.into()`.

It's also possible to consider the need for a `T::ZERO` as a language problem, because it's just a hack to work around the fact that `0` doesn't work as one would like. If we could, instead, use CTFE to define some way for types to use literals, then perhaps instead of `T: NumInfo`, you could use some sort of `T: FromIntegerLiteral`, and thus `0` would do what people rationally wish it would.

> [@gilescope](#):
>
> People say that one and zero are not necessary for std lib

If you'd like a polyfill that works on stable for them:

```rust
fn zero<T>() -> T where T: std::iter::Sum {
    std::iter::empty::<T>().sum()
}
fn one<T>() -> T where T: std::iter::Product {
    std::iter::empty::<T>().product()
}

```

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 10, 2022, 9:11pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/7 "2022-04-10T21:11:17Z")

</div>

Complete agreement with all of that: I think if we want to do this, we want several integer traits, not just one.

---

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 10, 2022, 10:48pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/8 "2022-04-10T22:48:22Z")

</div>

Good point about NonZeroU32 types.

In the spirit of baby steps, what's the smallest trait we could have? Would having MIN, MAX, and BITS as a single trait be a first baby step?

(Is signed is a bit easier to figure out if you can get hold of MIN.)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 10, 2022, 11:38pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/9 "2022-04-10T23:38:08Z")

</div>

> [@gilescope](#):
>
> In the spirit of baby steps, what's the smallest trait we could have? Would having MIN, MAX, and BITS as a single trait be a first baby step?

Something like a `num::Bounded` with `MIN` & `MAX`, maybe? Probably the most useful thing to see would be examples of code that could take advantage of such a trait, to answer questions like "what about `num::BigUint` that has `MIN` but not `MAX`?".

`BITS` is arguably weird in generic code, since one could say that `NonZeroU8` should be 7.994353... bits.

Hmm, maybe there's a nice holistic piece here by having a trait like `num::SaturatingFrom` (as discussed, IIRC, in [https://github.com/rust-lang/rfcs/pull/2484](https://github.com/rust-lang/rfcs/pull/2484)) and a corresponding trait with `MIN` & `MAX` that says what the range into which it saturates is.

---

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 11, 2022, 6:27am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/10 "2022-04-11T06:27:12Z")

</div>

Arguably if there's no upper bound then it's not Bounded. num::Bounded sounds good.

If we push this to the limits we get two or three traits:

`num::LowerBound`,

`num::UpperBound`,

and to be kind to the humans we can add `type Bounded = LowerBound + UpperBound`. (can we do that in rust yet?)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 11, 2022, 6:54am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/11 "2022-04-11T06:54:44Z")

</div>

> [@gilescope](#):
>
> and to be kind to the humans we can add `type Bounded = LowerBound + UpperBound` . (can we do that in rust yet?)

Well, it'd be `trait Bounded = LowerBound + UpperBound;`, using [trait\_alias - The Rust Unstable Book](https://doc.rust-lang.org/nightly/unstable-book/language-features/trait-alias.html) -- it's not a type.

---

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 11, 2022, 7:39pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/12 "2022-04-11T19:39:16Z")

</div>

Ok, I think this is the lot:

> **[Rust Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=d261da401ca62ea52837402c30265c5f)**
>
> A browser interface to the Rust compiler to experiment with the language

Should I turn this into a PR and we put it under a `num_bounds_trait` feature flag? (rightly or wrongly, atomicu32 and friends do not have min\_value defined upon them.)

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 12, 2022, 12:12am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/13 "2022-04-12T00:12:35Z")

</div>

> [@gilescope](#):
>
> Should I turn this into a PR

I'd suggest asking libs-api what they'd like to see for it. The best place is probably either their zulip stream [https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs) or making an issue and getting it nominated for a meeting.

For just adding a function here or there, a PR tends to be the right approach. But traits are setting a precedent and asking the ecosystem to adopt them, so they often want an RFC spelling out their intended semantics and the rationale for the design picked.

For example, since we'll have `impl const Default` or similar for optionally-const defaults, why it this `MIN` always-constants instead of functions that could also be non-const sometimes. (Not that I'm saying the constants are _wrong_ just that there's a choice to be made.) Or what is `Bounded::MIN` supposed to mean, and how does that interact with floats? For example, the [minimal element](https://en.wikipedia.org/wiki/Maximal_and_minimal_elements) of `f32` is `f32::NEG_INFINITY`, _not_ `f32::MIN`. (And how does the definition not say that `NAN`s are also minima?) For example, [std::numeric\_limits - cppreference.com](https://en.cppreference.com/w/cpp/types/numeric_limits) has `min`, `lowest`, and `denorm_min`. Should this have all those? Do we need a different version of these for floats? Etc.

Adding a constant for a specific type is easy, but giving something on a trait a meaning such that it can be usefully used generically is hard.

---

<div class="post-metadata">

**Author:** ![Dante-Broggi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dante-broggi/32/5798_2.png) [@Dante-Broggi](https://internals.rust-lang.org/u/Dante-Broggi)\
**Post date:** [April 12, 2022, 3:14am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/14 "2022-04-12T03:14:27Z")

</div>

> [@scottmcm](#):
>
> For example, [std::numeric\_limits - cppreference.com](https://en.cppreference.com/w/cpp/types/numeric_limits) […]
> 
> Adding a constant for a specific type is easy, but giving something on a trait a meaning such that it can be usefully used generically is hard.

So as another comparison on this note that Swift has both [SignedInteger](https://swiftinit.org/reference/swift/signedinteger) and [UnsignedInteger](https://swiftinit.org/reference/swift/unsignedinteger), each of which define `max` and `min` constants but have a common parent [BinaryInteger](https://swiftinit.org/reference/swift/binaryinteger) which defines neither, and [FloatingPoint](https://swiftinit.org/reference/swift/floatingpoint) defines `greatestFiniteMagnitude`, `leastNonzeroMagnitude`, and `leastNormalMagnitude`, etc. which are obviously distinct from the integer constants.

---

<div class="post-metadata">

**Author:** ![gilescope](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gilescope/32/2798_2.png) [@gilescope](https://internals.rust-lang.org/u/gilescope)\
**Post date:** [April 12, 2022, 8:02am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/15 "2022-04-12T08:02:19Z")

</div>

C++'s `min` looks wrong to me. Our `f32::min` is their `lowest`. We're not asking about what's the smallest value that can be represented. If people did want that, that would be a separate floating point specific trait.

I agree that we should probably call them `LowerFiniteBound` and `UpperFiniteBound`

zulip thread: [rust-lang](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/upper.2Flower.20bound.20num.20trait)

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [April 12, 2022, 1:31pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/16 "2022-04-12T13:31:07Z")

</div>

Apropos `std::numeric_limits`, it's worth noting that they're [proposing a set of individually specializable type traits](http://open-std.org/JTC1/SC22/WG21/docs/papers/2022/p1841r3.pdf) to supplement (and probably eventually deprecate) the monolithic `numeric_limits`.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [April 12, 2022, 11:56pm UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/17 "2022-04-12T23:56:49Z")

</div>

Semi-relevant: a PR to add checked equivalents of `Sum` and `Product` to `core`:

> <https://github.com/rust-lang/rust/pull/95485>
>
> Adds a checked version of \`sum\` and \`product\` to iterators,
> 
> Based on https://…github.com/RustCrypto/formats/pull/558 cc @tarcieri
> 
> Docs:
> 
> !\[rustdoc screanshot of checked\_sum\](https://user-images.githubusercontent.com/28781354/160898813-80f90500-ce47-49f0-b0ea-836cc7afce1c.png)
> !\[rustdoc scheanshot of checked\_product\](https://user-images.githubusercontent.com/28781354/160898882-a3c11505-ef41-41d3-8526-a0cfddd49f36.png)
> 
> Tracking issue: #95484

I get the original impetus for avoiding having something like `num-traits` in core, but it seems like they've had a long time to bake out-of-core.

`num-traits` has been versioned v0.2 for over 4 years. Is there really a reason to be concerned about having these traits in core at this point? It seems like they've had a long time to bake and people are generally happy about the shape of them.

Certainly another round of considering the design is in order, and I would expect a long period of such traits being nightly-only, but it seems like it's achievable to eventually stabilize such traits with the consideration that they're effectively immutable and inextensible.

tl;dr: I'm not sure there's much more research in this problem space which will be beneficial versus shipping something that will make most people happy.

Even if such traits were unstable and nightly-only, it seems like having them could greatly improve the internal implementation of the core numeric types, which presently have heavily macro-laden implementations that, in some cases, could be replaced with traits for expressing common functionality instead.

---

<div class="post-metadata">

**Author:** ![elidupree](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/elidupree/32/4304_2.png) [@elidupree](https://internals.rust-lang.org/u/elidupree)\
**Post date:** [April 13, 2022, 12:17am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/18 "2022-04-13T00:17:40Z")

</div>

> [@bascule](#):
>
> It seems like they've had a long time to bake and people are generally happy about the shape of them.

I can't speak for anyone else, but I'm not especially happy with the shape of the num-traits traits – they're certainly useful to me, but as I mentioned in [my post upthread](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/5), they don't provide nearly the amount of convenience for "just abstract over the primitive integer types" as I would have hoped, partly due to things that could easily be changed, and partly due to lack of compiler support for some of the things you might want.

Speaking of compiler support, if we brought something like NumOps into core, it might be ideal for it to be a `trait_alias` instead of a separate trait, and that's not stable yet (and I'm assuming wouldn't be backwards-compatible to change). I think there are probably a lot of similar issues, where the ultimate best design for the numeric traits depends on features that are not yet stable (or even not yet settled on by RFC).

On the other hand, I think there are a bunch of single-method traits that don't have any apparent design dilemmas, so it would probably be reasonable to start bringing some of them into core.

---

<div class="post-metadata">

**Author:** ![cmpute](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cmpute/32/9141_2.png) [@cmpute](https://internals.rust-lang.org/u/cmpute)\
**Post date:** [April 13, 2022, 4:51am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/19 "2022-04-13T04:51:09Z")

</div>

Just want to note that some people (including me) are not particularly satisfied with the interfaces defined in `num-traits` (see [here](https://github.com/rust-num/num-traits/issues/178) for example). `num-traits` hasn't changed much for a long time mostly because the maintainer doesn't want to do break changes (which contradicts with the idea that moving features out of std can help the features evolve more freely imo...)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [July 12, 2022, 4:51am UTC](https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/20 "2022-07-12T04:51:27Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
