Why does rust allow `&i32 + i32` but not for `&i32 == i32`?

See this code below, x == y is not allowed, but x + y is ok. What's the reason behind this design?

fn main() {
    let x = 2;
    let y = &x;
    println!("{}", x == y);
    println!("{}", x + y);
}

compile error message:

error[E0277]: can't compare `{integer}` with `&{integer}`
 --> src/main.rs:4:22
  |
4 |     println!("{}", x == y);
  |                      ^^ no implementation for `{integer} == &{integer}`
  |
  = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
  = help: the following other types implement trait `PartialEq<Rhs>`:
3 Likes

Because Add<i32> is implemented for i32 while PartialEq<i32> is not implemented for &i32.

yes, but why

1 Like

"why" for these is usually either:

  1. these implementations need to be written for every combination of the types, and nobody thought to add this one.

  2. or this would overlap with some other implementation, make types ambiguous, and break everything.

I'm not sure which one it is in this case.

This is indeed an annoying papercut. I guess at least one, maybe even the primary reason is that while PartialEq<T> can be implemented for T& and vice versa, Eq cannot (because it requires both operands have the exact same type), even though i32 == &i32 is just as total an order as i32 == i32 is. The same goes for Ord and PartialOrd.

Personally I don't like that &i32 + i32 works.

Some possible reasons why &i32 == i32 doesn't exist:

  1. A lot of people implement == for their own types and then they would face the question: should they also do &T == T for consistency with std?

  2. It would break some type inference.

However, type inference is already hit and miss. For instance: 6u32 == 5u8.into() compiles but 5u8.into() == 6u32 doesn't.

5 Likes