I have a struct defined as:

use nalgebra::{
    allocator::Allocator, DefaultAllocator, Dim, DimName, MatrixN, RowVectorN, VectorN, U1,
}; // 0.22.0

pub struct Filter<Order: Dim + DimName>
where
    DefaultAllocator:
        Allocator<f64, Order, Order> + Allocator<f64, Order> + Allocator<f64, U1, Order>,
{
    a: MatrixN<f64, Order>,
    b: VectorN<f64, Order>,
    c: RowVectorN<f64, Order>,
    d: f64,
    x: VectorN<f64, Order>,
}

In my unit test module, I want to construct an instance of Filter:

mod tests {
    use super::*;
    use nalgebra::U2;

    fn a_filter() -> Filter<U2> {
        let a: MatrixN<f64, U2> = MatrixN::from_iterator([1., -0., 1., 0.].into_iter());

        Filter {
            a,
            b: VectorN::zeros(),
            c: RowVectorN::zeros(),
            d: 0.,
            x: VectorN::zeros()
        }
    }
}

The call to MatrixN::from_iterator() results in compile errors. Similar errors occur in the calls to ::zeros():

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:22:44
   |
22 |         let a: MatrixN<f64, U2> = MatrixN::from_iterator([1., -0., 1., 0.].into_iter());
   |                                            ^^^^^^^^^^^^^ multiple `from_iterator` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:26:25
   |
26 |             b: VectorN::zeros(),
   |                         ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:27:28
   |
27 |             c: RowVectorN::zeros(),
   |                            ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

error[E0034]: multiple applicable items in scope
  --> src/lib.rs:29:25
   |
29 |             x: VectorN::zeros(),
   |                         ^^^^^ multiple `zeros` found
   |
   = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
   = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
   = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
   = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

It is not clear to me why Rust is unable to figure out the correct from_iterator to use. Is it because I've had to specify DefaultAllocator in the definition of Filter? If so, what's the cleanest workaround for this?

1

There are 1 best solutions below

0
On BEST ANSWER

TL; DR; A workaround for your code:

fn a_filter() -> Filter<U2> {
    let a = MatrixN::<f64, U2>::from_iterator([1.0, -0., 1., 0.].iter().copied());

    Filter {
        a,
        b: VectorN::<f64, U2>::zeros(),
        c: RowVectorN::<f64, U2>::zeros(),
        d: 0.,
        x: VectorN::<f64, U2>::zeros()
    }
}

You have to specify the order in the call of zeros() instead of guessing it from the return type.

The from_iterator has the additional problem that array::into_iter() does not return an iterator over the values but over references to the values, just like iter() (yes, is is perplexing, and there is a lint for that, IIRC), so you need to add a copied() to get the proper iterator type.


This is the minimum code that shows your error (playground):

use nalgebra::{
    VectorN, U3
};
fn main() {
    let x: VectorN<f64, U3> = VectorN::zeros();
}

The error is:

error[E0034]: multiple applicable items in scope
 --> src/main.rs:5:40
  |
5 |     let x: VectorN<f64, U3> = VectorN::zeros();
  |                                        ^^^^^ multiple `zeros` found
  |
  = note: candidate #1 is defined in an impl for the type `nalgebra::Matrix<N, R, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, C>>::Buffer>`
  = note: candidate #2 is defined in an impl for the type `nalgebra::Matrix<N, R, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, R, nalgebra::Dynamic>>::Buffer>`
  = note: candidate #3 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, C, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, C>>::Buffer>`
  = note: candidate #4 is defined in an impl for the type `nalgebra::Matrix<N, nalgebra::Dynamic, nalgebra::Dynamic, <nalgebra::DefaultAllocator as nalgebra::allocator::Allocator<N, nalgebra::Dynamic, nalgebra::Dynamic>>::Buffer>`

If you look careful at the candidates, they are just a the full names of:

candidate #1: Matrix<N, R, C, _>
candidate #2: Matrix<N, R, Dynamic, _>`
candidate #3: Matrix<N, Dynamic, C, _>`
candidate #4: Matrix<N, Dynamic, Dynamic, _>`

So they have something to do with that Dynamic thing... If you look at the documentation it is not very helpful, but if you look at the example in the zeros() function it has a hint:

let v = Vector3::<f32>::zeros();
let dv = DVector::<f32>::zeros(3);
let m = Matrix2x3::<f32>::zeros();
let dm = DMatrix::<f32>::zeros(2, 3);

Wait... didn't it take 0 arguments? Well, looking at the code, although the documentation does not say it, it looks like zeros() takes as many arguments as they have Dynamic in the generic types. And Vector3<T> is an alias for Vector<T, U3>, DVector<T> is an alias for Vector<T, Dynamic> and so on.

You may still think that the compiler could deduce the function anyway, because the return type and the argument numbers are different for each version of zero(), but that is not how the compiler works: there is no function overload in Rust. If a function name resolves to more than one function it is an error.

Consider this much simpler code that shows a similar error:

struct Foo<T> {
    t: T,
}

impl Foo<u8> {
    fn new() -> u8 {
        0
    }
}

impl Foo<u32> {
    fn new() -> u32 {
        0
    }
}

fn main() {
    let t: u8 = Foo::new(); // error!
}

Note that it doesn't matter if both functions return the same or different types, or even whether they have the same number of arguments, it is always a compiler error.

The workaround for my code is:

fn main() {
    let t: u8 = Foo::<u8>::new();
}