Description
Consider this code:
struct Foo;
impl Foo {
fn foo(&self) {
println!("Foo");
}
}
trait Bar {
fn foo(&self);
}
impl Bar for Foo {
fn foo(&self) {
println!("Bar");
}
}
fn main() {
let mut f = Foo;
f.foo();
}
Unlike a method name conflict between two traits, Rust will compile this code, which will produce:
Foo
One might conclude that the inherent method (i.e. belonging to the type itself) Foo::foo()
has priority over the trait method Bar::foo()
. Yet, if we change the signature of Foo::foo()
to fn foo(&mut self)
in this code, suddenly the program outputs:
Bar
So it would seem the type of arguments also plays some role in which method is chosen. To try and understand the rules behind it, I created the following table which shows the output for each combination of self
's type in Foo::foo()
and Bar::foo()
:
Bar↓ Foo→ | &Self | &mut Self | Self |
---|---|---|---|
&Self | Foo | Bar | Foo |
&mut Self | Foo | Foo | Foo |
Self | Bar | Bar | Foo |
Looking at this, I think I can deduce that:
- Inherent methods indeed have priority over trait methods when types are equal.
- The priority of types is
&mut Self
<&Self
<Self
.
That said, these rules are not terribly intuitive, and I'm unsure how they stack up against more complex method signatures. It would be good to have documentation about this.
Another concern of mine, however, is the inconsistency between this and a situation involving multiple trait methods conflicting. In that situation, rustc gives an error and asks the programmer to specify which trait's method should be used via UFCS. I'd prefer something like that over the current situation, though I'm not sure it's possible to do backwards-compatibly.