0

Think below code, impl multiple times both for struct and traits:

mod m {
    pub trait Foo {
        fn xyzzy(&self) { println!("foo!"); }
    }
    
    pub trait Bar {
        fn xyzzy(&self) { println!("bar!"); }
    }
    
    pub trait Quux: Foo+Bar {
        fn xyzzy(&self) { println!("quux!"); }
    }
    
    pub struct X;
    impl X {
        pub fn xyzzy(&self) { println!("XXXXX self!"); }
    }
    impl Foo for X {}
    impl Bar for X {}
    impl Quux for X {}
}

use m::X;

fn main() {
    let x = X;
    x.xyzzy();
    {
        use m::Foo;
        x.xyzzy();  // prints "foo!"
    }
    {
        use m::Quux;
        x.xyzzy();  // prints "quux!"
    }
}

I want the result as below order:

XXXXX self!
foo!
quux!

But the result will be:

XXXXX self!
XXXXX self!
XXXXX self!

What's wrong here and how to implement the goal?

James Yang
  • 476
  • 5
  • 6

2 Answers2

2

Because of how method resolution works, when you have a trait method and an inherent method with the same receiver (&self), you will always get the inherent method. If you want the trait method, you have to call it as an associated function.

{
    use m::Foo;
    Foo::xyzzy(&x);
}
{
    use m::Quux;
    Quux::xyzzy(&x);
}

Another thing you can do is make X::xyzzy an associated function.

impl X {
    pub fn xyzzy(_this: &Self) { println!("XXXXX self!"); }
}

And then call it as an associated function.

X::xyzzy(&x);

Then it won't be involved in method resolution, and the trait methods will be found when the traits are in scope.

Something that you may encounter is this rule:

Then, for each candidate T, add &T and &mut T to the list immediately after T.

This means if you have a method that takes &mut self, a method that takes &self, and a method that takes self all in scope, then the self method will be called. However, this is not a clear or sustainable way to call a specific trait's method, The associated function syntax is certain to call the intended method.

drewtato
  • 6,783
  • 1
  • 12
  • 17
1

You can use a fully qualified path:

mod m {
    pub trait Foo {
        fn xyzzy(&self) { println!("foo!"); }
    }
    
    pub trait Bar {
        fn xyzzy(&self) { println!("bar!"); }
    }
    
    pub trait Quux: Foo+Bar {
        fn xyzzy(&self) { println!("quux!"); }
    }
    
    pub struct X;
    impl X {
        pub fn xyzzy(&self) { println!("XXXXX self!"); }
    }
    impl Foo for X {}
    impl Bar for X {}
    impl Quux for X {}
}

use m::X;

fn main() {
    let x = X;
    x.xyzzy();
    {
        use m::Foo;
        <X as Foo>::xyzzy(&x);  // prints "foo!"
    }
    {
        use m::Quux;
        <X as Quux>::xyzzy(&x);  // prints "quux!"
    }
}
Richard Neumann
  • 2,986
  • 2
  • 25
  • 50
  • 2
    This is not a cast, this is called _fully qualified path_, or _UFCS_ (_Universal Function Call Syntax_). https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls. – Chayim Friedman Jul 02 '23 at 17:03