Why can't you disambiguate via cast on a variable

From the playground:

    println!("{}", (element as &mut Foo<18>).foo(16));

That's a bit different than (bar as [the trait] Foo<4>). There is no &mut Foo<18> trait, so above, you're talking about ($Expression as $Type) -- which is a cast, like @jofas mentioned.

Moreover, you may have noticed the suggestion

error[E0782]: expected a type, found a trait
  --> src/main.rs:33:37
   |
33 |     println!("{}", (element as &mut Foo<18>).foo(16));
   |                                     ^^^^^^^
   |
help: you can add the `dyn` keyword if you want a trait object
   |
33 |     println!("{}", (element as &mut dyn Foo<18>).foo(16));
   |                                     +++

Which does indeed compile, performing a cast to the &mut dyn Foo<18> type and[1] dynamically dispatching to the method. On edition 2015 and edition 2018, the dyn indicator is optional for backwards compatibility reasons,[2] and the original code compiles.

All in all, I think any variation on ($Expression as $...) is too ambiguous to fly, especially since some of them are valid code in older editions, which would be quite confusing. But maybe other possibilities would be entertained.

// Spit-balling
element.foo::<in Foo<18>>(101);

You could search IRLO to see if it's come up before.


As for alternatives that work today...

    // you also do this which is clearly but a lot bulkier but is clearer
    <Struct as Foo<18>>::foo(element, 101);

This usually also works.

    <_ as Foo<18>>::foo(element, 101);

For this particular example, you could also

pub trait Quz {
    fn quz<const X: usize>(&mut self, bar: u64) where Self: Foo<X> {
        self.foo(bar);
    }
}

impl<T: ?Sized> Quz for T {}

// ...

    element.quz::<18>(101);

  1. modulo optimization ↩︎

  2. the dyn indicator didn't used to exist and you just had to know if you were looking at a type context or a trait context, plus some corner cases ↩︎

3 Likes