Equality

When comparing for equality in C#, this refers to testing for equivalence in some cases (also known as value equality), and in other cases it refers to testing for reference equality, which tests whether two variables refer to the same underlying object in memory. Every custom type can be compared for equality because it inherits from System.Object (or System.ValueType for value types, which inherits from System.Object), using either one of the abovementioned semantics.

For example, when comparing for equivalence and reference equality in C#:

var a = new Point(1, 2);
var b = new Point(1, 2);
var c = a;
Console.WriteLine(a == b); // (1) True
Console.WriteLine(a.Equals(b)); // (1) True
Console.WriteLine(a.Equals(new Point(2, 2))); // (1) False
Console.WriteLine(ReferenceEquals(a, b)); // (2) False
Console.WriteLine(ReferenceEquals(a, c)); // (2) True

record Point(int X, int Y);
  1. The equality operator == and the Equals method on the record Point compare for value equality, since records support value-type equality by default.

  2. Comparing for reference equality tests whether the variables refer to the same underlying object in memory.

Equivalently in Rust:

#[derive(Copy, Clone)]
struct Point(i32, i32);

fn main() {
    let a = Point(1, 2);
    let b = Point(1, 2);
    let c = a;
    println!("{}", a == b); // Error: "an implementation of `PartialEq<_>` might be missing for `Point`"
    println!("{}", a.eq(&b));
    println!("{}", a.eq(&Point(2, 2)));
}

The compiler error above illustrates that in Rust equality comparisons are always related to a trait implementation. To support a comparison using ==, a type must implement PartialEq.

Fixing the example above means deriving PartialEq for Point. Per default, deriving PartialEq will compare all fields for equality, which therefore have to implement PartialEq themselves. This is comparable to the equality for records in C#.

#[derive(Copy, Clone, PartialEq)]
struct Point(i32, i32);

fn main() {
    let a = Point(1, 2);
    let b = Point(1, 2);
    let c = a;
    println!("{}", a == b); // true
    println!("{}", a.eq(&b)); // true
    println!("{}", a.eq(&Point(2, 2))); // false
    println!("{}", a.eq(&c)); // true
}

There is no direct equivalence to reference equality in Rust, since not everything is a reference. However, when you have two references, you can check for their reference equality with std::ptr::eq()

fn main() {
    let a = 1;
    let b = 1;
    println!("{}", a == b); // true
    println!("{}", std::ptr::eq(&a, &b)); // false
    println!("{}", std::ptr::eq(&a, &a)); // true
}

Another way to compare for reference equality is to convert the references to raw pointers and compare them using ==.

See also:

  • Eq for a stricter version of PartialEq.