Deref coercion for equality and addition

I'm failing to understand some really core basic ideas about deref coercion.

fn main() {
  let x = 3;
  let y = &x;
  println!("{}", x + y); // doesn't work, op not defined for integer and &integer
  println!("{}", x == y); // same issue
}

why doesn't deref coercion happen here. Both + and == are method calls (trait impls)?

I think you may be misunderstanding what deref coercion is. A deref coercion converts a reference to something that implements the Deref trait into a reference to the type it dereferences to. Things that implement Deref are generally smart pointer types, and deref coercion is intended to provide an easy way to use whatever is behind the smart pointer. In your case, you have an integer, which isn't a smart pointer so there is nothing for it to dereference to.

The feature I think you might be expecting instead is the automatic dereferencing applied to method calls. That doesn't trigger here because it isn't using the dot syntax for method calls.

However, neither of these are the actual problem here, since Add is defined for all combinations of integer types and references. The problem the compiler is having is figuring out which integer type you want. Adding a type annotation solves it.

In the case of equality, however, Eq expects both sides to be the same type, so it does require a manual dereference. This shows the fact that you are comparing by value, not by reference.

So, overall, something like this works:

fn main() {
  let x : u8 = 3;
  let y = &x;
  println!("{}", x + y);
  println!("{}", x == *y);
}
2 Likes

So you're totally right that I was mixing up deref coercion and automatic dereferencing. I definitely meant the latter.

It makes sense that Eq would force manual dereferencing for the reason you stated, thanks for clearing that up!

Oddly enough, this code is actually working for me now, don't know what changed

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

So I guess I'm just asking for clarification about the part of your answer where you talked about rust needing a type annotation. Why would it be confused about which integer type I want for the addition operation?

Thanks for all your help, auto-derefencing was scaring me away from rust but your answer makes a lot of sense.

Probably because you haven't actually specified a type in let x = 3;. Instead you've left it to rustc to choose an integer type for you, in this case probably i32. For numeric values outside the range of that default type the assignment would generate a compile-time error.

Just adding the explicit dereference to the equality actually seems to fix the original example. Trying to figure out the types for the equality seems to throw off the inference of the types for the addition as well. Without the ambiguous equality, the usual default (which I think is i32) is inferred.