Is it by design that assert_eq! does not deref like a function call would?

Hi friends,

I'm a bit of a Rust noob here, and I'm taking a dive into automatic dereferencing rules. While that was happening, I noticed that the assert_eq! macro doesn't do what I'd expect.

Here, I have a function that takes two references and compares them for equality:

let a = [1, 2];
let b = [1, 2];

fn assert(c: &[i32; 2], d: &[i32; 2]) {
  assert_eq!(c, d);
}

assert(&&&&a, &&b);

This works how I would expect it to based on the rules I am reading. However, this fails:

assert_eq!(&&&&a, &&b);

So, I took a look at the macro and I think I understand why, but I'm curious if it's by design. The relevant section (https://doc.rust-lang.org/src/core/macros/mod.rs.html#42-75):

macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    // The reborrows below are intentional. Without them, the stack slot for the
                    // borrow is initialized even before the values are compared, leading to a
                    // noticeable slow down.
                    panic!(r#"assertion failed: `(left == right)`
  left: `{:?}`,
 right: `{:?}`"#, &*left_val, &*right_val)
                }
            }
        }
    });
}

Would it be desirable to have assert_eq! deref, and is something like this just plain wrong?

// Same functionality but derefs bc of the function call
macro_rules! my_assert_eq {
    ($left:expr, $right:expr) => ({
          fn test<T: std::cmp::PartialEq + std::fmt::Debug>(left_val: &T, right_val: &T) {
            if !(*left_val == *right_val) {
              panic!(r#"assertion failed: `(left == right)` left: `{:?}`, right: `{:?}`"#, &*left_val, &*right_val)
            }
          }
          test($left, $right);
    });
}

With this example macro, I'm able to produce the desired functionality:

let a = [1, 2];
let b = [1, 2];

fn assert(c: &[i32; 2], d: &[i32; 2]) {
  assert_eq!(c, d);
}

my_assert_eq!(&&&&a, &&b);

Your assert function is no fair comparison because it specifies the precise types it expects while assert_eq must work generically. In particular, equality testing in Rust can even work in some cases where the left side and the right side of the == comparison are entirely different types, as long as there is a matching implementation L: PartialEq<R>. Your proposed alternative my_assert_eq macro, too, imposes the restriction of both sides needing too have the same type.

Note that is should be the case that assert_eq!(expr1, expr2) works exactly in the same cases as expr1 == expr2 does, as long as the types involved also implement Debug. Since == is way more important than assert_eq, you probably want to focus on the fact that &&&&a == &&b doesn't work and discuss ways to, perhaps, improve the Rust language in that regard, if you have any ideas how to solve these "problems".

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.