ProgrammingLibrary Developer

What are PartialEq and Eq in Rust, what contract do they enforce when comparing values, and why is it important to maintain the strictness of equality in user-defined types?

Pass interviews with Hintsage AI assistant

Answer.

Background

In Rust, the traits PartialEq and Eq arise from the philosophy of type safety — all fundamental operations for collections (HashMap, HashSet) are based on a strict definition of equality. The traits determine whether objects of two types can be compared using == and whether a type is required to implement "total" equality (Eq) or "partial" equality (PartialEq).

Problem

Incorrect implementation of PartialEq/Eq can lead to incorrect operation of collections, where basic mathematical properties are violated: comparison with itself, symmetry, transitivity. Furthermore, an incorrect Eq can lead to objects being "lost" in collections or unexpected duplicates occurring.

Solution

PartialEq is implemented for types where comparison might not be possible for all values (for example, f32, where NaN != NaN). Eq is meant only for "strict" (total) relations. User-defined types should implement comparison in strict accordance with these contracts.

Example code:

#[derive(PartialEq, Eq)] struct Point { x: i32, y: i32, } let p1 = Point { x: 1, y: 2 }; let p2 = Point { x: 1, y: 2 }; assert!(p1 == p2); // true

Key features:

  • PartialEq allows for "partial" comparison — there can be values that do not compare correctly (for example, NaN).
  • Eq requires a total relation: x == x must always be true; all properties of the relation must be maintained.
  • Correct implementation of these traits is critical for collections and standard library functions.

Trick questions.

Why does the standard library implement only PartialEq for the f32 type, but not Eq?

Because according to IEEE-754, NaN != NaN, i.e., the property x == x is not maintained for all x, which is a necessary property for Eq.

Is it mandatory to explicitly implement Eq if PartialEq is implemented manually?

Yes, if the type supports total equality (x == x is always true), Eq must be manually implemented as well, otherwise some structures will fail to compile with your type.

Can a user implement PartialEq "asymmetrically" (x == y, but y != x)?

Technically yes, but it leads to incorrect behavior of collections and is considered a bug.

Common mistakes and anti-patterns

  • Ignoring necessary properties of comparison, making PartialEq "flawed."
  • Not implementing Eq for those types where it is possible, breaking the functionality of HashMap/HashSet.
  • Implementing symmetry "in their own way," violating the specification.

Real-life example

** Negative case

A user implemented PartialEq for a type that only compares one field, ignoring the others. As a result, HashSet "loses" duplicates.

Pros:

  • Easy implementation, can compare quickly.

Cons:

  • False matches, loss of uniqueness.

** Positive case

Using #[derive(PartialEq, Eq)] or implementing their own version of comparison, taking into account all business logic, ensuring the required properties.

Pros:

  • Collections work correctly, strict behavior.

Cons:

  • Requires careful and thoughtful design approach.