Type-inference and items-resolution?

use std::marker::PhantomData;

struct A {}
struct B {}

struct X<T> {
    _m: PhantomData<T>
}

impl X<A> {
    fn init(a: u32) -> Self {
        Self { _m: PhantomData }
    }
}

impl X<B> {
    fn init(b: i32) -> Self {
        Self { _m: PhantomData }
    }
}

fn main() {
    let p: X<A> = X::init(1u32);
}

The error is: error[E0034]: multiple applicable items in scope.

Is there an exact reason why this doesn’t work, even when the binding is type-annotated?

The type annotation for this is X::<A>::init(1u32).

p: X<A> is an annotation for init()'s return type. Often Rust likes to know the type of a method immediately at the call site, rather than matching possible methods based on their types.

1 Like

Because those are inherent methods. It looks like it might work because it's Self, but consider that it could instead have been impl X<C> { fn init(c: f32) -> X<A> { ... } }, and things are weirder.

Make a trait, though, and it'll work:

use std::marker::PhantomData;

struct A {}
struct B {}

struct X<T> {
    _m: PhantomData<T>
}

trait Init<T> : Sized {
    fn init(_: T) -> Self;
}

impl Init<u32> for X<A> {
    fn init(a: u32) -> Self {
        Self { _m: PhantomData }
    }
}

impl Init<i32> for X<B> {
    fn init(b: i32) -> Self {
        Self { _m: PhantomData }
    }
}

fn main() {
    let p: X<A> = X::init(1u32);
}

https://play.rust-lang.org/?gist=fb838eb35422f1d80d851c80115a3c77

1 Like

That would work, but I forgot to mention that the second init takes two arguments which I assume is not possible in this way. But I guess this is pointing more towards method overloading which rust doesn’t support.

You can simulate a second argument by using a tuple for the 2nd init. So something like:

impl Init<(i32, i32)> for X<B> {
    fn init(b: (i32, i32)) -> Self {
        Self { _m: PhantomData }
    }
}
1 Like

But then it wouldn’t be really ergonomic to use the api and it’s probably better to just use two different method names xD.

Very true. init with one argument is often better spelled From::from anyway, too :slightly_smiling_face:

1 Like