3

My program has a bunch of functions that operate on generic integer. They are usually of the following form:

use num::{FromPrimitive, Integer, ToPrimitive};
use std::cmp::Ord;
use std::ops::{Add, Mul};

fn function<'a, I>(n: &'a I) -> I
where
    I: Integer + Clone + FromPrimitive + ToPrimitive,
    for<'b> &'b I: Mul<Output = I> + Add<Output = I> + Ord,
{

}

I want to alias the generic type requirements:

I: Integer + Clone + FromPrimitive + ToPrimitive,
for<'b> &'b I: Mul<Output = I> + Add<Output = I> + Ord,

so that I won't need to rewrite them every time. Initially, I thought macros would help but it looks like they don't work like in C so I looked for another way.

I found a way to do it for the first requirement. One has to apply the default implementation on the defined trait over any type T.

trait GInteger: Integer + Clone + FromPrimitive + ToPrimitive {}
impl<T: Integer + Clone + FromPrimitive + ToPrimitive> GInteger for T {}

Then I can simply write:

I: GInteger

instead of

I: Integer + Clone + FromPrimitive + ToPrimitive,

How can I alias the second requirement? Is it possible?

for<'b> &'b I: Mul<Output = I> + Add<Output = I> + Ord,
Ömer Erden
  • 7,680
  • 5
  • 36
  • 45
jam
  • 803
  • 5
  • 14

1 Answers1

3

No it's not possible to use a new trait for this.

While it's possible to include the second requirement into the trait definition...

trait GInteger: Integer + Clone + FromPrimitive + ToPrimitive
where
    for<'b> &'b Self: Mul<Output = Self> + Add<Output = Self> + Ord,
{
}

rustc will not elaborate the where clause for you, so in the declaration of function() you still need to write the where for<'b> &'b I: ... bound. It is a known bug.

fn function<I: GInteger>(n: &I) -> I
where
    for<'b> &'b I: Mul<Output = I> + Add<Output = I> + Ord,  // meh
{
    n * n
}

If you're using nightly Rust, you could use trait alias (RFC 1733) instead, which exactly solves this problem.

#![feature(trait_alias)]

use num::{FromPrimitive, Integer, ToPrimitive};
use std::cmp::Ord;
use std::ops::{Add, Mul};

// Define a trait alias
trait GInteger = Integer + Clone + FromPrimitive + ToPrimitive
where
    for<'b> &'b Self: Mul<Output = Self> + Add<Output = Self> + Ord;

// Just use it
fn function<I: GInteger>(n: &I) -> I {
    n * n
}
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005