# Rust and numeric computation

**URL:** <https://internals.rust-lang.org/t/rust-and-numeric-computation/20425>\
**Category:** Uncategorized\
**Created:** [March 2, 2024, 11:06am UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425 "2024-03-02T11:06:22Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![jimy-byerley](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jimy-byerley/32/9180_2.png) [@jimy-byerley](https://internals.rust-lang.org/u/jimy-byerley)\
**Post date:** [March 6, 2024, 6:08pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/21 "2024-03-06T18:08:57Z")

</div>

That pre-RFC looked nice, but what is the need of seeling traits ? I mean understand the purpose is to forbid other crates to implement them, but what is the need in the specific case of `Int` and `Float` ?

By separating eventual numeric traits in core than numeric traits implemented in other crates is keeping the issue of API duplication described in my initial post: using traits from core and concurrent traits from other crates leads to have in the same crate functions implemented with one trait and its methods and functions asside with an other trait and different methods for the same thing, bringing confusion if not verbosity (because when 2 traits provide the same method in the same scope, one has to use `<T as Trait>::method(...)` syntax ...)

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 6, 2024, 9:01pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/22 "2024-03-06T21:01:08Z")

</div>

The purpose of sealing `core::primitive::Integer` and `core::Primitive::Float` specifically _is_ to forbid implementations in other crates / on other types. This makes it possible to add new functionality to the traits as we add new functionality to the primitive types. Additionally, it permits the traits to represent the existing `self`-taking methods that rely on the types being `Copy` instead of switching to `&self`. The primary reason is that exactly mirroring existing functionality that exists over existing type sets is easier to justify and simpler to stabilize than trying create a richer trait system.

Furthermore, depending on how much we teach the coherency checker, both traits being `#[sealed] #[fundamental]` would allow `impl<T: Integer> MyTrait for T` and `impl<T: Float> MyTrait for T` to not overlap. This mutual exclusivity is actually a fairly big deal and what allows replacing macro-generated functionality across primitive types with generic functionality without causing coherency issues.

And yet further still, it's potentially desirable to have `T: Integer` bounds imply further `where` bounds on `&T` to provide the by-ref `core::ops` impls that exist on the primitive arithmetic types. Standard `trait`s do not currently elaborate `where` bounds and are reasonably unlikely ever to, but (unstable) trait aliases (usable as bounds but not directly implementable) currently do. `#[sealed]` traits could reasonably elaborate `where` bounds (they have different semver compatibility reasoning), but trait aliases also confer the ability to potentially move shared bounds to a shared supertrait without breaking references to e.g. `<_ as Integer>::from_ne_bytes` since that's not writable with trait aliases.

It doesn't preclude adding a separate `std::num` hierarchy in the future if the project decides it's worth the effort; it still makes sense to be able to talk about the language primitive type sets `{integer}` and `{float}`.

---

<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:** [March 6, 2024, 9:49pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/23 "2024-03-06T21:49:47Z")

</div>

> [@jimy-byerley](#):
>
> It is stunning that they went in the direction of removing these traits instead of fixing the design issues o.O

And delay the release of 1.0 indefinitely?Have you ever shipped software?

---

<div class="post-metadata">

**Author:** ![bluss](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bluss/32/2264_2.png) [@bluss](https://internals.rust-lang.org/u/bluss)\
**Post date:** [March 6, 2024, 10:38pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/24 "2024-03-06T22:38:59Z")

</div>

Thanks for writing about an important topic @jimy-byerley.

These are the points I think are important - because of work on and with ndarray.

- Generic literals for integers and floats would be a big quality of life upgrade, and it would be necessary for us to feel that numerics is a tier 1 feature in Rust

- More flexibility in indexing and slicing syntax and traits, to enable multidimensional indexing and slicing. This probably needs work on the custom DST RFC as well. I can't help but think of Python here that enabled advanced indexing features in its syntax, that are never used in core Python (but numpy and the rest use it).

- Specialization or overloading of some kind to enable calling specific functions for f32, f64 etc. (The solution I know I have today is the `T: 'static` bound and dispatch on TypeId.)

> [@jimy-byerley](#):
>
> **If the rust core team never improves these points**

The Rust community has the RFC process and that's the way to go to make improvements in this area too. We need to be lucky to have contributors with time and interest in this area that can do this. I'm sorry I haven't been one of them.

---

<div class="post-metadata">

**Author:** ![djc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/djc/32/1592_2.png) [@djc](https://internals.rust-lang.org/u/djc)\
**Post date:** [March 6, 2024, 11:07pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/25 "2024-03-06T23:07:48Z")

</div>

> [@bluss](#):
>
> The Rust community has the RFC process and that's the way to go to make improvements in this area too. We need to be lucky to have contributors with time and interest in this area that can do this. I'm sorry I haven't been one of them.

(Or money to fund such contributors.)

---

<div class="post-metadata">

**Author:** ![jimy-byerley](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jimy-byerley/32/9180_2.png) [@jimy-byerley](https://internals.rust-lang.org/u/jimy-byerley)\
**Post date:** [March 7, 2024, 6:39pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/26 "2024-03-07T18:39:28Z")

</div>

shipped software ... discovered bugs, and introduced temporary regressions to patch it. I unfortunately did ^.^ but rust 1 is [from 8 years ago](https://blog.rust-lang.org/2015/05/15/Rust-1.0.html) and no solution landed in ever since ? I think that's mainly what left me think this feature was not a priority.

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [March 11, 2024, 1:38pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/27 "2024-03-11T13:38:04Z")

</div>

I agree that the numerics side of Rust leaves much to be desired. My personal pet peeve is the design of arithmetic operation traits (`Add`, `Mul`, `MulAssign` etc), which works horribly with generic code, since you need to implement basically all combinations of `val OP val`, `&val OP val`, `val OP &val` and `&val OP &val` to have reasonable expression writing ergonomics (and similarly for `OpAssign`). Worse, implementing all that stuff for numeric types is painful, but at least automatable with macros. But it's impossible to encapsulate those requirements in a trait bound, and one must repeat a significant amount of them, because there is currently no way to put a constraint on `Self` that is

```rust
for<'a> &'a Self: Add<Self, Output=Self>

```

You can technically write a trait with a `where`-bound like that, but it doesn't work as a modularization tool, because the bound will need to be explicitly repeated on every type and function using a generic with this restriction. Also, type checker is prone to barfing out some _really_ bad errors when bounds of the form `for<'a> &a T: Foo` are present, mostly because of type checker's limitations than something inherently wrong with those bounds.

This is also why I think that trying to introduce more kitchen-sink traits to deal with ergonomics issues of numerics is a dead end. There is just no way to _really_ express the semantics of numeric code in current Rust. At best you can restrict numeric traits to `Sized + Copy + Freeze` types with some `#[fundamental]` tactically sprinkled in, but it still won't work the way `eigen` templates work. These assumptions immediately exclude a large number of important potential applications, like heap-allocated `BigInt`, and you _still_ can't write a simple arithmetic expression without hitting the sharp corners of by-value vs by-ref operations. On top of that you get more complex code, likely worse compile times, likely worse optimization.

* * *

That said, I'm a bit confused by your conclusion:

> [@jimy-byerley](#):
>
> it is easier to write computational code in C or C++.

I get that using `eigen` is simpler, but C? There is literally nothing C can do that Rust can't do, better. C also doesn't have generics or overloading, and basically can't handle static array sizes, since arrays decay to pointers. You can always write Rust like you write C, even use macros, and you'll still be better off.

In fact, for scientific prototyping I wonder how many of your problems are self-inflicted. _Why_ do you even need to be generic over integers and floats? It's a real issue for foundational libraries like `nalgebra` and `ndarray`, but end-user applications should just choose a couple of specific numeric types and stick with them. Done, all of your generic problems gone in one fell swoop.

A reasonable counterargument is "but what if I choose `f64` but later decide that `f32` is better for speed and is sufficiently precise", or vice versa, "what if I go with `f32` but later realise I need the precision of `f64`". You still don't need to be generic in all your code, though. You can solve that problem by introducing a single typedef

```rust
type Float = f64;

```

and using exclusively that type for all your type bounds. If you need to swap your floating-point type, just change that typedef, done. You have the potential to get confusing errors if some duck-typed API turns out to be slightly different between `f32` and `f64`, but that's still as good as you would have with C++ templates, and I doubt there would be many such differences.

Similarly, for your integers just use

```rust
type SInt = i32;
type UInt = u32;

```

It's not like you are likely to need `u8` or `u16` out of the blue anyway, and if you need to swap between `i32` and `i64`, it works good enough.

Again, that's not a modular approach, you can't change those typedefs in your dependencies (unless you vendor them), but I believe it's good enough to solve the practical end-user problems while the proper language features are slowly worked out.

* * *

Regarding `From`-conversions, while nothing technically says they need to be lossless (and I'm sure they aren't in plenty of important cases), it's not an unreasonable assumption for the end user. If we add a lossy `f32 -> u32` or `u64 -> f32` conversion, I'm sure there will be confused users who got a bug because they lost precision. That's not good.

My position is that `From`-conversions are for situations where there is _a single obvious right way to do it_. If there are multiple ways to do a conversion, or if it has some caveats (because it may me fallible, or lossy, or just have a nasty edge case), or if the conversion is unexpectedly expensive, or there is even a slight possibility that the conversion would work differently in the future (require extra parameters, or extra runtime preconditions, or return a different type), then the operation shouldn't be a `From` impl. Add it as a method, or as a separate trait. Thank me later.

The core use of traits is generic code, and generic code just can't work with subtle type-specific constraints, by definition. The end user will pass in a `T: From<U>` without knowing the subtle edge cases of that impl, because there just isn't a proper place to document those subtleties, nor a reason to expect them to exist in the first place. The generic function will hit a nasty bug or performance degradation, because it has no way to guard against those edge cases at all. And even if you know that your `From` impl has some edge cases, the issue can be triggered deep in the generic call stack, making it impossible for the end user to expect or debug such issues.

Thus I think `impl From<usize> for f32` is a bad idea, even though nothing _technically_ prevents that impl. Lossy conversion traits may be fine, but that won't do much to solve the issue of ergonomics, and the "lossy" conversion may be lossy for different reasons, which may be better modeled with different traits anyway (e.g. for integers, truncation `i32 -> i8` and sign-cast `i32 -> u32` are both potentially problematic, but for different reasons).

* * *

Note that if you're fine with the semantics of `as`-casts and just want to have some genericity, you can easily define a `CastAs<T>` trait wrapping that operation. Implementation of it requires some boilerplate, but `num-traits` already did that work for you with their [NumCast](https://docs.rs/num-traits/latest/num_traits/cast/trait.NumCast.html) trait. It seems to have the semantics that you want, allowing int-to-float lossy casts, but disallowing narrowing or sign-discarding casts between integers. I recall seeing the simpler `as`-cast trait in the wild as well (maybe in some older version of `num-traits`).

* * *

Regarding the generic literals, personally I don't get the appeal. It's not hard to use explicit `T::from` conversions, and you'd need to put extra trait bounds on the generic function anyway, either `T: From<Float>` or `T: ParseFloat`. I get that having to write and read `T::from(1.0)` is worse than just `1.0`, but this can mostly be solved with a local definition:

```rust
fn foo<T: From<Float>>(..) {
    let f = T::from;
    let x = f(1.0) * bar + f(.35);
    // etc
}

```

That's just marginally longer than a plain literal, so personally I don't find it a burden to use. You can cut out even more of those conversions if you put a bound like `T: Mul<Float, Output=T>` on your function, allowing to write `bar * 1.0` instead of `bar * f(1.0)`. A symmetric bound `Float: Mul<T, Output=T>` allows you to write `1.0 * bar`, although this can be problematic to use in more generic code due to trait coherence issues.

And again, all of those issues are gone if you use a specific type instead of generic functions.

* * *

Overall, I believe that numeric code isn't as bad to write as you imply, moreso if you don't try to go fully generic. On the other hand, one can't expect the end users to know all of those niche tricks, and in generic library-level code the complexity becomes hard to work around. I think this really needs language-level support. I just don't believe it can be patched around by a couple of new traits, since the fundamental ergonomics and performance issues would remain.

---

<div class="post-metadata">

**Author:** ![Timo](https://avatars.discourse-cdn.com/v4/letter/t/c4cdca/32.png) [@Timo](https://internals.rust-lang.org/u/Timo)\
**Post date:** [March 11, 2024, 3:08pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/28 "2024-03-11T15:08:16Z")

</div>

The genericity of size problem can be partially solved within the existing traits system. In [https://github.com/linalg-rs/rlst](https://github.com/linalg-rs/rlst) we are building a linear algebra library that abstracts around stack allocated or heap allocated data containers and supports n-dimensional tensors.

For example, to instantiate a 3-tensor with dimensions (4, 5, 6) on the stack you can say:

```rust
let arr = rlst_static_array!(f64, 4, 5, 6)

```

or to instantiate the same array on the heap you can say

```rust
let arr = rlst_dynamic_array!(f64, [4, 5, 6])

```

Both arrays have the same functionality and are indistinguishable in use. The numbers of dimensions (here 3) is hard-coded in the type as const expression. However, there are constructs to take lower-dimensional slices (e.g. take an n-1 dimensional slice of a n-dimensional array, which then has n-1 as type parameter) or promote a type to higher dimensions (e.g. interpret a one-dimensional vector as a two-dimensional matrix with just one column). All this works within the current type system, though is a bit cumbersome to implement.

The biggest problem is arithmetic with const expression, e.g. the statement

```rust
let arr = rlst_static_array!(f64, 4, 5, 6)

```

is a proc-macro that internally multiplies 4 x 5 x 6 and then instantiates an array with 120 elements on the stack. But it is not possible to write e.g.

```rust
let arr = rlslt_static_array!(f64, DIM1, DIM2)

```

where DIM1 and DIM2 are const expression parameters. This would only work with generic const expressions from nightly.

---

<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:** [March 11, 2024, 6:23pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/29 "2024-03-11T18:23:35Z")

</div>

> [@afetisov](#):
>
> My position is that `From`-conversions are for situations where there is _a single obvious right way to do it_.

Note that I (somewhat) recently added a bunch of new docs about this, with libs-api signoff: [https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from](https://doc.rust-lang.org/std/convert/trait.From.html#when-to-implement-from)

We came up with 4 ways in which `From` is typically restricted, and that future implementations should also follow.

Notably, _even when_ there's a single obvious way to convert between the types, it _still_ might not be a good idea to have `From` implemented.

---

<div class="post-metadata">

**Author:** ![jimy-byerley](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jimy-byerley/32/9180_2.png) [@jimy-byerley](https://internals.rust-lang.org/u/jimy-byerley)\
**Post date:** [March 16, 2024, 2:16pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/30 "2024-03-16T14:16:42Z")

</div>

Your the problem you faced in your library is yet an other example 👍

This issue with generic constant expressions was exactly what I meant in my initial post: quite often we need to concatenate/multiply dimensions of matrices and vectors, but the lack of generic constant expresssion makes it impossible for statically allocated matrices

---

<div class="post-metadata">

**Author:** ![jimy-byerley](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jimy-byerley/32/9180_2.png) [@jimy-byerley](https://internals.rust-lang.org/u/jimy-byerley)\
**Post date:** [March 16, 2024, 3:46pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/31 "2024-03-16T15:46:13Z")

</div>

> My personal pet peeve is the design of arithmetic operation traits (`Add`, `Mul`, `MulAssign` etc), which works horribly with generic code, since you need to implement basically all combinations of `val OP val`, `&val OP val`, `val OP &val` and `&val OP &val` to have reasonable expression writing ergonomics

This is a pain I agree, I personnaly opt for a different way: I implement almost only `Op<&T> for &T` even for small types, and let the compiler optimize the by-ref code into by-value code when it is appropriate. This leaves me with a lot of explicit-referencing in my expression (which is also a pain) but at least it is DRY.

As a side-topic I sometimes consider it would be good to have implicit-referencing in rust, so we would not be obliged to write `&` everywhere in our code ... referencing or not could systematically be guessed by the compiler according to the called functions signatures. Anyway ...

* * *

> I get that using `eigen` is simpler, but C?

I do not agree that one could do in rust anything you could in C, I meant not that easily. In C you can

- easily cast between numbers (sometimes too easily ...)
- overload functions (not fully replacing traits, but helping in dealing with non-generic code)
- write macros implementing functions overloads for specific array sizes
- use litterals in macro-generated code, because the litteral type is only infered after macro-expansion

For instance you can write the following combining these advantages:

```rust
#define define_vec(T, N) \
  typedef struct { \
    T array[N], \
  } vec ## N \
  size_t size(vec ## N * a) { return N; }
  vec#N add(vec ## N * a, vec ## N * b) { ...}

define_vec(float, 3);
define_vec(float, 4);
vec3 a;
vec4 b;
vec3 c = add(&a, &a);
vec4 d = add(&b, &b);

```

This not perfect C code but you got the idea. Not as simple and readable as Eigen, but definitely something.

* * *

> In fact, for scientific prototyping I wonder how many of your problems are self-inflicted
> 
> ...
> 
> It's not like you are likely to need `u8` or `u16` out of the blue anyway, and if you need to swap between `i32` and `i64`, it works good enough.

For prototyping, all what you said after is true: one do not really need generics for prototyping and instead can statically set the number types and even sizes. This is true for prototyping but not for writing libraries or functions for a large project.

The problem is: often I need `u8` as much as `u64`

Let say I want to write a blur function like in [openCV](https://docs.opencv.org/3.4/d4/d86/group __imgproc__ filter.html#ga8c45db9afe636703801b0b2e440fce37). This function is intended to operate on images which pixels have an arbitrary precision. So I need number traits or I have to implement it many times for specific elemnt types, or to use dynamic element typing like in openCV implementation. I cannot use macros for this in rust because as function overloading is not possible, I could not combine the specialized functions names in other macros. Obviously fixing `UInt = u32` is not satisfying because in order to write efficient code (image manipulation here) I need to use the appropriate element type. And it is not the same for every operations along the program.

* * *

About `NumCast`, I do use it. My concern only is the same as everything in `num-traits`:

- it is not a standard and thus the community and crates are fragmented about using it or an other competing solution
- it is a trait providing methods that are redundants with the methods from `core`, hence it is convenient to use only with objects of a generic type. not with objects of concrete type (or you need to use the verbose turbofish operator ...). As mentioned in my initial post, this is leading to writing code with a certain set of functions when it is concrete types and a completely different set of functions when it is generic.

---

<div class="post-metadata">

**Author:** ![Timo](https://avatars.discourse-cdn.com/v4/letter/t/c4cdca/32.png) [@Timo](https://internals.rust-lang.org/u/Timo)\
**Post date:** [March 16, 2024, 4:14pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/32 "2024-03-16T16:14:21Z")

</div>

If I had a choice of one feature to move from nightly to stable it would be generic const expressions. I would love to see progress on this.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [March 16, 2024, 7:21pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/33 "2024-03-16T19:21:52Z")

</div>

> [@jimy-byerley](#):
>
> In C you can […] overload functions

Not that way\[1\], you can't. In C++ pretending to be C you can, but that's _not C_. Even with `-std:gnu17` (GNU extensions to C17) you need ` __attribute__ ((overloadable))`.

> [@jimy-byerley](#):
>
> - write macros implementing functions overloads for specific array sizes
> - use literals in macro-generated code, because the literal type is only inferred after macro-expansion

This works the same in Rust. In fact you can write the _exact_ same thing you've written for pseudo-C but for Rust: [[playground]](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aa3150af1c4559908c47c7611394647a)

```rust
macro_rules! define_vec {($T:ident, $N:literal) => {
    paste! {
        pub struct [<vec$N>] {
            array: [$T; $N],
        }
        
        impl [<vec$N>] {
            fn size(&self) -> usize { $N }
            fn add(&self, other: &Self) -> Self { todo!() }
        }
    }
}}

define_vec!(f32, 3);
define_vec!(f32, 4);

let a: MaybeUninit<vec3> = MaybeUninit::uninit();
let b: MaybeUninit<vec4> = MaybeUninit::uninit();
let c = a.assume_init_ref().add(a.assume_init_ref());
let d = b.assume_init_ref().add(b.assume_init_ref());

```

or without the blatant UB: [[playground]](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=92c7853d73b5ddbb8904f6ad72076136)

```rust
macro_rules! define_vec {($T:ident, $N:literal) => {
    paste! {
        #[derive(Default)]
        pub struct [<vec$N>] {
            array: [$T; $N],
        }
        
        impl [<vec$N>] {
            fn size(&self) -> usize { $N }
            fn add(&self, other: &Self) -> Self { todo!() }
        }
    }
}}

define_vec!(f32, 3);
define_vec!(f32, 4);

let a = vec3::default();
let b = vec4::default();
let c = a.add(&a);
let d = b.add(&b);

```

> [@jimy-byerley](#):
>
> I cannot use macros for this in rust because as function overloading is not possible, I could not combine the specialized functions names in other macros.

Trait functions _are_ the way to do function overloading in Rust, it's just a bit more syntactically heavy than ad-hoc overloading. Yes, core doesn't provide a way to concatenate identifiers together (and barely does so on nightly, [`concat_idents!`](https://doc.rust-lang.org/stable/std/macro.concat_idents.html) only works for naming existing names), but proc macros do, and the [paste](https://docs.rs/paste/latest/paste/) crate is effectively standard in all but being available without a cargo dependency declaration. But you don't even need to do this, either: all you need is modules which provide the same API shape, and you can do `$module::name` to select the correct name.

* * *

But I do actually agree both that autoref for operators would've been preferable in retrospect to expecting `Copy` types to provide all of `T $op T`, `&T op T`, `T op &T`, and `&T op &T`; and that accepting `T` where `&T` is expected (semantics: moves the value into a temporary which is then referenced, i.e. `&{$expr}`) would be an interesting bit of ergonomics (although it could lead to people towards cloning where referencing would be sufficient, such as impl `AsRef<T>` parameters can do today.)

* * *

1. You can use `_Generic` to make type-generic _macros_, but this requires knowing the set of supported type names when you define the macro.

---

<div class="post-metadata">

**Author:** ![quaternic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quaternic/32/10440_2.png) [@quaternic](https://internals.rust-lang.org/u/quaternic)\
**Post date:** [March 16, 2024, 8:38pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/34 "2024-03-16T20:38:18Z")

</div>

Random idea: If you can implement something for `type UInt = u32; // or u64` with the same code, then you could (unidiomatically) do something like

```rust
mod u32 {
    type UInt = u32;
    include!("same_code.rs");
}
mod u64 {
    type UInt = u64;
    include!("same_code.rs");
}

```

The tooling might not play along perfectly, but this feels preferable to writing all the impls as a `macro_rules` macro. I'll have to try the next time I need to just duplicate code.

---

<div class="post-metadata">

**Author:** ![jimy-byerley](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jimy-byerley/32/9180_2.png) [@jimy-byerley](https://internals.rust-lang.org/u/jimy-byerley)\
**Post date:** [March 17, 2024, 9:14am UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/35 "2024-03-17T09:14:11Z")

</div>

> Not that way, you can't

🤔 true, in stndard C I need ` _Generic` ...

I didn't knew `paste` ! This is nice stuff thanks. So yes one can do the same in rust.

> or without the blatant UB

It was only for the concept 😉

---

<div class="post-metadata">

**Author:** ![afetisov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/afetisov/32/8508_2.png) [@afetisov](https://internals.rust-lang.org/u/afetisov)\
**Post date:** [March 19, 2024, 1:20pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/36 "2024-03-19T13:20:23Z")

</div>

I did it once, for writing tests in several modules which had syntactically mostly the same public-facing API. Not good, not terrible. For dozens of mostly-same simple test functions, certainly better than writing macros. But the IDE was confused about the module inclusion, basically assuming that the submodule is included in a single place. The pattern itself is also a bit obscure. The solution worked, but I would think twice about using it for any complicated code, and I certainly wouldn't want to use it for anything public-facing.

My currently preferred solution for dealing with this kind of repetitive code is a combination of crates [duplicate](https://docs.rs/duplicate/latest/duplicate/) and [macro\_rules\_attribute](https://docs.rs/macro_rules_attribute/latest/macro_rules_attribute/). `duplicate` allows easy duplication of code for impls and simple functions over integers, while `macro_rules_attribute` allows deduplicating the `duplicate` attributes themselves. Neither crate depends on `syn` (at least with default features turned off), which means they add basically no compile time cost even for simple crates.

That doesn't work if similar snippets of code must be placed in different modules, though.

---

<div class="post-metadata">

**Author:** ![bert](https://avatars.discourse-cdn.com/v4/letter/b/9e8a1a/32.png) [@bert](https://internals.rust-lang.org/u/bert)\
**Post date:** [March 20, 2024, 3:37am UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/37 "2024-03-20T03:37:54Z")

</div>

For some prior art on numeric genericness, the Julia language is an interesting place to look. The [conversion and type promotion story](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/) is really nice and makes math “just work” for the vast majority of cases. Every pair of numeric types has a defined common type in which both are pretty much representable. (Although Rust would probably want to be stricter here — Julia has e.g., `255u8 + 127i8 == 126u8`, which is not great.)

Numeric literals actually seems like it shouldn't be too hard. Rust already does some inference on integer literals; doing similar inference on floating point should be possible and non-breaking? I know that Swift has traits for all kinds of expressible-by-literal, such as [`ExpressibleByFloatLiteral`](https://developer.apple.com/documentation/swift/expressiblebyfloatliteral).

---

<div class="post-metadata">

**Author:** ![helgee](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/helgee/32/11959_2.png) [@helgee](https://internals.rust-lang.org/u/helgee)\
**Post date:** [March 23, 2024, 7:52am UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/38 "2024-03-23T07:52:33Z")

</div>

Hi folks, I am new here 👋

I was curious about Rust and started working on a [space mission design library](https://github.com/lox-space/lox) last year which we are now using as the backend for an ESA-funded Python library.

This discussion is very interesting to me because I ran into all the issues that @jimy-byerley mentioned in the past few weeks.

I also agree with @bert that Julia would be a great source of inspiration for generic numerics. I've used it since 0.1 and only jumped ship because I missed ADTs and pattern matching after some excursions into functional programming and Julia lacks AOT compilation which makes distribution and TDD painful.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [March 29, 2024, 6:05pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/39 "2024-03-29T18:05:13Z")

</div>

> [@bert](#):
>
> Rust already does some inference on integer literals; doing similar inference on floating point should be possible and non-breaking?

Rust does the same kind of inference on floats already: `1.0` will be an `f32` or an `f64` depending on how you use it.

---

<div class="post-metadata">

**Author:** ![cuviper](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cuviper/32/1897_2.png) [@cuviper](https://internals.rust-lang.org/u/cuviper)\
**Post date:** [March 29, 2024, 6:09pm UTC](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425/40 "2024-03-29T18:09:49Z")

</div>

Yes, but integer and float inference both only work with concrete types. You can't use literals at all for generic types.

[Previous page](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425.md?page=1)

[Next page](https://internals.rust-lang.org/t/rust-and-numeric-computation/20425.md?page=3)
