rusttypenum

Use different impl when type parameters are the same


I have an impl with two generic typenum parameters. The impl's function should return a different type when the parameters are the same. (The different type is a more compact representation that can only be realized when the type parameters are the same.) Is it possible to use a different impl based on type equality? The naive method below produces a "conflicting implementations" error because Rust does not take the more specific implementation.

extern crate typenum;
use typenum::Unsigned;

use std::ops::Mul;
use std::marker::PhantomData;

struct Matrix<N: Unsigned, M: Unsigned> {
    n: usize,
    m: usize,
    elements: Vec<f64>,
    _marker: PhantomData<(N, M)>
}

// The more compact representation
struct SquareMatrix<N: Unsigned> {
    n: usize,
    elements: Vec<f64>,
    _marker: PhantomData<(N)>
}

impl<N: Unsigned, D: Unsigned, M: Unsigned> Mul<Matrix<D, M>> for Matrix<N, D> {
    type Output = Matrix<N, M>;
    fn mul(self, rhs: Matrix<D, M>) -> Self::Output {
        unimplemented!()
    }
}

// The more specific implementation
impl<N: Unsigned, D: Unsigned> Mul<Matrix<D, N>> for Matrix<N, D> {
    type Output = SquareMatrix<N>;
    fn mul(self, rhs: Matrix<D, N>) -> Self::Output {
        unimplemented!()
    }
}

Solution

  • With specialization (which is still unstable as of Rust 1.16.0), you can. Basically, all you need is to declare the items in the more general implementation with default to say "this can be specialized".

    #![feature(specialization)]
    
    impl<N: Unsigned, D: Unsigned, M: Unsigned> Mul<Matrix<D, M>> for Matrix<N, D> {
        default type Output = Matrix<N, M>;
    
        default fn mul(self, rhs: Matrix<D, M>) -> Self::Output {
            unimplemented!()
        }
    }
    
    // The more specific implementation
    impl<N: Unsigned, D: Unsigned> Mul<Matrix<D, N>> for Matrix<N, D> {
        type Output = SquareMatrix<N>;
    
        fn mul(self, rhs: Matrix<D, N>) -> Self::Output {
            unimplemented!()
        }
    }