Help with generic Traits

Hi, So I'm trying this:

#[derive(Clone, Debug)]
pub struct SymMonomial<C: Integer, I, P> {
	pub coefficient : C,
	pub powers : Vec<(I, P)>
}


impl<C: Integer, I, P> Mul<i64> for SymMonomial<C, I, P>{
	type Output = SymMonomial<C, I, P>;

	fn mul(self, rhs: i64) -> Self::Output{
		SymMonomial{coefficient: self.coefficient * rhs, powers: Vec::new()}
	}
}

Where the Integer trait comes from the num crate. However the compiler is complaining that the product has a mismatched types. If I try to do rhs as C then it complains for non-scalar cast. Does anyone know what is the best way to achieve what I'm trying to do naively?

self.coefficient * rhs is trying to compute C * i64, so either a trait bound is needed on the impl that allows that operation, or you need another solution. I think that typically you'd implement Mul<C> instead and require C: Mul<Output=C> ? That's one approach.

Hmm however I need more something like Mul<Integer, Output=C>, e.g. a class C for which the multiplication with an integer is defined and it produces a C. However the compiler says:

error: the trait `num::Integer` cannot be made into an object

Do you have any suggestions on how to go around that. I sort of need something like a template, but want to keep it rusty.

Then you can introduce another type parameter D, and require that C * D => C like below. (You could make it more generic by not requiring the Output to be C.)

impl<C: Integer, D: Integer, I, P> Mul<D> for SymMonomial<C, I, P>
    where C: Mul<D, Output=C>,
{
	type Output = SymMonomial<C, I, P>;

	fn mul(self, rhs: D) -> Self::Output {
		SymMonomial{coefficient: self.coefficient * rhs, powers: Vec::new()}
	}
}
1 Like

Thanks, that did not cross my mind at all.

I don't know which integer types you are going to use. Is it a disappointment that integers can't cross multiply? I.e the only primitive integer type that i64 can be multiplied with is i64. With custom Integer implementations, it can be a bit more interesting, of course.

In general I'm going to use only a single type for C,I and P. However, it is going to be a small library for manipulating symbolic integers (e.g. polynomials over the integers), so I thought to make it a bit more generic if someone else would later find it usefull. And I know it is a shame, but currently I'm using the num crate and they have the trait Integer implemented for all integers.

Actually the more annoying thing is the lack of ergonomics on the operator overloading by reference, so if I want it to be pretty for the users I have to this by value, thus I need to make the whole class copyable... but oh well...