Methods disambiguation with methods wrappers

Hi,

I have a trait that I don't want/can't to change and I want to write a wrapper around it.
The final point is to provide a struct to the user that implement the trait but with a changed returned type:

pub trait Model {
   fn evaluate(&mut self);
}
pub struct UserModel;

impl Model for UserModel {
    fn evaluate_wrapper(&mut self) -> Result<()> {
        self.evaluate();
        Ok(())
    }
}

This code works but I would like the method wrapper to have the same name as the method trait, which is possible thanks to: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#fully-qualified-syntax-for-disambiguation-calling-methods-with-the-same-name.
However, in my case, I cannot make it work, as I don't know how to implement the method wrapper. I tried the following:

impl Model for UserModel {
    fn evaluate(&mut self) -> Result<()> {
        //self.evaluate();
        //<self as Model>::evaluate();
        //<Self as Model>::evaluate();
        Ok(())
    }
}

How can I refer in a method that I want to call the Self object for a given trait implementation ?

Also If I use the first option, the code compile.

impl Model for UserModel {
    fn evaluate(&mut self) -> Result<()> {
        self.evaluate();
        Ok(())
    }
}

However, it seems it is not calling the right method, but calling itself instead. This can be seen by changing the code to the following, that won't compile due to a mismatch of method signature:

impl Model for UserModel {
    fn evaluate(&mut self) -> Result<()> {
        Ok(self.evaluate())
    }
}

The compilation error is: expected (), found enum std::result::Result

I am quite puzzled about the last part that did compiled at first but wasn't at all want I expected.

Thanks in advance!

That's because you aren't returning this Ok you create.

If the expression ends with semicolon, it is converted to the statement and evaluates to (). To use thiis expression as a return value of block (or, in this case, function), just omit the semicolon. Note that in the previous block of code there is no semicolon after Ok(()).

I’m only guessing from your description that there’s another trait that’s also called Model in a different module with a method that’s also called evaluate. (You could’ve actually presented that other trait in your code, too, to make things less confusing.) Let’s assume that the path to that other Model trait is path::to::Model. Then you can call it like this:

path::to::Model::evaluate(self)

Btw, the fully qualified syntax would’ve been

<Self as path::to::Model>::evaluate(self)

Edit: Here’s a playground link for illustration purposes.

To expand on @steffahn answer, here's an example of wrapping evaluate():

Playground link

Right, I also created an example in the playground myself just seconds before you posted yours. Though you seem to have understood OPs question differently. I honestly don’t really know what they meant by:

You can’t really “implement a trait but with a changed return type”, or at least I don’t really get the mindset behind this view.


Thinking about it again, perhaps your interpretation is closer to what OP meant, then the point about the path being qualified goes away and the syntax of course becomes just Model::evaluate(self), as you presented in your playground.

It was a typo in the example, I fixed it, thanks a lot. The error message is still the same

Thanks for the solution, it does solve my issue.
There is actually no other trait with the same method, I just didn't realize I could call the method and pass the self argument, I was always trying to do self.method.
Thanks a lot.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.