1

I'm still new to rust and I'm a bit puzzled by this tiny detail below. From what I understood so far is that == and eq() are pretty much equivalent. I wonder why is dereferencing y required for the operator version but not for the function call. I was expecting that no dereferencing should be required at all since the eq method expects a reference to y anyways.

use std::cmp::{Eq, PartialEq};
struct X{}
struct Y {}
impl PartialEq<Y> for X{
    fn eq(&self, rhs: &Y)->bool{
        true
    }
}

impl PartialEq for X{
    fn eq(&self, rhs: &X)->bool{
        true
    }
}

impl Eq for X {}

fn main() {
    let x = X{};
    let y = Y{};
    
    let f1 = |y: &Y| x == *y;
    let f2 = |y: &Y| x.eq(y);
    
}

Playground

mkmostafa
  • 3,071
  • 2
  • 18
  • 47
  • Because the `eq()` method takes a reference for the parameter `rhs`. In other words: you pass a *reference* to `eq()`, so if you already have a reference you'll not need to dereference it. – Jesper Jul 08 '22 at 10:24
  • 1
    Also because Rust will autoref (and autoderef) the subject of a method call, but not operators. And since `PartialEq` is defined in terms of `X` and `Y` that's what Rust wants. OP can implement `PartialEq<&Y> for X` and now the first lambda will compile but the second won't. – Masklinn Jul 08 '22 at 10:27
  • @Jesper I'm very convinced about that part. I even stated clearly that I consider this the expected behavior. My problem is what I understand is that `==` and `eq` are equivalent so I do not expect to have to deref for `==` for the same reason that you stated in your comment. – mkmostafa Jul 08 '22 at 10:34
  • @Masklinn are there any references to this discrepancy between operators and function calls? – mkmostafa Jul 08 '22 at 10:36
  • 1
    Not directly about the discrepancy. But [this post](https://stackoverflow.com/questions/53341819/what-is-the-relation-between-auto-dereferencing-and-deref-coercion/53344847#53344847) explains the machinery that is invoked for function calls (which simply isn't there for operators). – Caesar Jul 08 '22 at 11:36

1 Answers1

3

Because eq() and == are not equivalent.

Even without autoref, when you call a == b, Rust does not execute PartialEq::eq(a, b). Rather, it executes PartialEq::eq(&a, &b). That is, Rust calls eq() with automatically-referenced operands when using the operator.

So, x == *y is basically (&x).eq(&*y), but x == y is (&x).eq(&y), which uses a double reference for y and therefore doesn't work.

When you write x.eq(y), however, Rust does not perform any adjustment to y (well, almost), but it does borrow x because of autoref. So this is the same as (&x).eq(y), which is the same as the operator version (&x).eq(&*y).

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77