Discussing some aspects of Method Calls

⚓ Rust    📅 2025-06-26    👤 surdeus    👁️ 7      

surdeus

Warning

This post was published 44 days ago. The information described in this article may have changed.

Chapter 5 of the book talks about Automatic Dereferencing with the notable example of method calls.

Call Expressions have a search-process to find the method in an instance.method() call. This algorithm enables ergonomic read and use since (*instance).method(), (&instance).method() and such are later added by the compiler.

For example in instance.method() the compiler will know the type of instance but the guessing-feature (par above) doesn't know whether it's for instance, *instance, &instance, &mut instance...

So it creates candidates until the it matches, say fn method(&mut self).

A complete example of that process is given in the reference:

For instance, if the receiver has type Box<[i32;2]> , then the candidate types will be Box<[i32;2]> , &Box<[i32;2]> , &mut Box<[i32;2]> , [i32; 2] (by dereferencing), &[i32; 2] , &mut [i32; 2] , [i32] (by unsized coercion), &[i32] , and finally &mut [i32] .

  • My first question is: Are the candidate types independent of the type of the instance ? In other words, do instance, &instace, &&instance all generate the same candidate list? I assume so, or that one is a subset of the others, but I'm unsure.
  • PS: What happens if 2 of the types in the list have the same method? Like x and &x ? (or it could be that the sentence below is correct, I am hesitating now.)

From that candidate list only one matches the receiver's type (that in the method signature.)

Case 1: No traits
Expectedly so, this fails to compile:

Snippet 1: No Traits (click for more details)

However, this overloading of foo is actually allowed for traits (and compounded by A's foo as well):

Case 2: Default Traits

Snippet 2: Default Implementations (click for more details)

I think this is error prone. If you Derive a trait, or simply implement an external trait with a default {} that could lead to bugs since a.foo() could be choosing methods from any implemented traits.

Some of the rules I found

  • Compiler only complains when they resolve to the same method and the same receiver; a name+method like foo(&self) in B and C clashes, but won't if one is not &self.
    • When they clash, one needs to disambiguate the code with a full path B::foo(&c) or C::..
  • Compiler takes first self then &self then &mut self; this is important for homonymous methods.

There isn't much of a question for this last part, but it is just very confusing, so any notes, remarks or corrections are welcome.

3 posts - 2 participants

Read full topic

🏷️ rust_feed