Ambiguous associated type fix

I have a struct:

pub struct PPSpline<T>
{
    k: usize,
    t: Vec<f64>,
    c: Option<Array1<T>>,
    n: usize,
}

which can be constructed with:

    pub fn new(k: usize, t: Vec<f64>, c: Option<Vec<T>>) -> Self 

When I attempt to construct it as follows I understand why I get a cannot infer type compilation error:

 let pp1 = PPSpline::new(2, vec![1.,1., 2., 2.], None);

So if I try to specify a fully qualified path I get:

 let pp1 = PPSpline::f64::new(2, vec![1.,1., 2., 2.], None);
error[E0223]: ambiguous associated type
   --> src\splines\spline_f64.rs:403:19
    |
403 |         let pp2 = PPSpline::f64::new(2, vec![1.,1., 2., 2.], None);
    |                   ^^^^^^^^^^^^^
    |
help: if there were a trait named `Example` with associated type `f64` implemented for `spline_f64::PPSpline<_>`, you could use the fully-qualified path
    |
403 |         let pp2 = <spline_f64::PPSpline<_> as Example>::f64::new(2, vec![1.,1., 2., 2.], None);
    |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I don't understand why this doesn't work and why the compiler has decided to offer confuding help about hypothetical traits that I am not trying to use. How can I re-formulate this to specify the type as f64 directly?

Incidentally should this read "if there was a trait" instead of "if there were a trait"?

Not a native speaker myself, but I can find discussions on the internet suggesting it’s technically correct (but also kinda correct either way):

1 Like

The correct syntax for specifying generic parameters is PPSpline::<f64>::new.

It seems like without the < the compiler has gotten very confused, hence the not very helpful error message.

"If there were" is perfectly valid English, if you search for "subjunctive mood" you may find more on the subject.

1 Like

Your error here is mostly syntactical, you need to use a turbofish in that place:

    let pp1 = PPSpline::<f64>::new(2, vec![1.,1., 2., 2.], None);

Thanks both. Yes the compiler error led me on the wrong track. Turbo fish to the rescue.

For completeness: Another possible place to annotate a type would be the None, as in:

    let pp1 = PPSpline::new(2, vec![1., 1., 2., 2.], None::<Vec<f64>>);

You could also annotate the binding as in

    let pp1: PPSpline<f64> = PPSpline::new(2, vec![1., 1., 2., 2.], None);

though given that that’s the original compiler suggestion, you probably wanted to avoid the duplicate PPSpline. Finally, if you dislike the “::” of turbofish, it’s also always a possibility to instead wrap the whole type in another layer of <> bracketing:

    let pp1 = <PPSpline<f64>>::new(2, vec![1., 1., 2., 2.], None);

If you on the other hand love turbo fish, :: is still optionally allowed in types, too.

    let pp1 = <PPSpline::<f64>>::new(2, vec![1., 1., 2., 2.], None);

You can even add <> or ::<> to parameter-less types; so taken to the extreme, feel free to write

    let pp1 = <PPSpline::<f64::<>>>::new(2, vec![1., 1., 2., 2.], Option::<Vec::<f64::<>>>::None::<> {});

to show off your niche Rust syntax knowledge. (These last two examples are a joke; it's valid syntax, but please don't actually do that.)

2 Likes

That is all quite a useful reference. Thx

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.