Help with generic Traits


#1

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?


#2

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.


#3

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.


#4

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()}
	}
}

#5

Thanks, that did not cross my mind at all.


#6

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.


#8

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.


#9

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…