Why would two reference counters pointing to the same allocation be unequal?

Viewed 257

I've recently came across this in the Rust documentation about the implementation of PartialEq for Rc:

/// If `T` also implements `Eq` (implying reflexivity of equality),
/// two `Rc`s that point to the same allocation are
/// never unequal.

Surely by definition two pointers pointing two the same position in memory are equal (because they are the same value)? Why would this not be the case if two values are only PartialEq and not Eq?

2 Answers

Rust's pointer comparison don't compare the pointers, but the pointed-to values. This is the case for &T, &mut T, Box<T>, Rc<T>, Arc<T>, etc., all but the raw pointers *const T and *mut T themselves. Those smart pointers usually have an extra method (std::rc::Rc::ptr_eq in this case) for actual pointer comparison.

This is similar to how Debug on those pointers prints the pointed-to value rather than the address, and you need the Pointer trait to print the actual address: Rust isn't very address-focused.

Now, if you have a type such as f64 which doesn't have a transitive == (that is, it implements PartialEq but not Eq) and wrap it in an Rc, you also get non-transitivity:

fn main() {
    let a = std::rc::Rc::new(std::f64::NAN);

    println!("a == a?: {}", a == a);
    println!(
        "a == a but with pointer comparison?: {}",
        std::rc::Rc::ptr_eq(&a, &a)
    );

    // But:
    let answer = std::rc::Rc::new(42);
    // surely this will have a different address
    let another_answer = std::rc::Rc::new(42);

    println!("answer == another_answer?: {}", answer == another_answer);
}

prints:

a == a?: false
a == a but with pointer comparison?: true
answer == another_answer?: true

If T happens to implement Eq as well as PartialEq, the current implementation indeed does a pointer comparison, using the yet-to-be-stabilized specialization feature.

See also:

Because not all values are equal to themselves. NaN, for example.

Related