What is the difference between `Eq` and `PartialEq`?

If I impl the Eq as std said:

impl Eq for foo {}

What will happend?
And I can't find any method or notation to use Eq?
will compiler treat Eq just like Partial Eq?

Thank you!

5 Likes

From the documentation:

Eq

Trait for equality comparisons which are equivalence relations.

This means, that in addition to a == b and a != b being strict inverses, the equality must be (for all a, b and c):

reflexive: a == a;
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.

This property cannot be checked by the compiler, and therefore Eq implies PartialEq, and has no extra methods.

PartialEq

Trait for equality comparisons which are partial equivalence relations.

This trait allows for partial equality, for types that do not have a full equivalence relation. For example, in floating point numbers NaN != NaN, so floating point types implement PartialEq but not Eq.

Formally, the equality must be (for all a, b and c):

symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.

Note that these requirements mean that the trait itself must be implemented symmetrically and transitively: if T: PartialEq and U: PartialEq then U: PartialEq and T: PartialEq.

What will happen?

You will implement the respective traits for type foo. It is up to you to ensure the contract defined in the documentation is upheld. If you don't uphold the contract, bad / illogical things might happen.

I can't find any method or notation to use Eq

Trait Eq inherits trait PartialEq. All it does is refine the contract.

a == a // valild assuming type A implements Eq

Will compiler treat Eq just like PartialEq?

As mentioned previously, Eq inherits PartialEq (i.e. PartialEq needs to be implemented for a type for Eq can be implemented). See the book on traits.

9 Likes

The docs for PartialEq say:

Trait for equality comparisons which are partial equivalence relations.

This trait allows for partial equality, for types that do not have a full equivalence relation. For example, in floating point numbers NaN != NaN, so floating point types implement PartialEq but not Eq.

Formally, the equality must be (for all a, b and c):

symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.

Whereas the docs for Eq say

Tr ait for equality comparisons which are equivalence relations.

This means, that in addition to a == b and a != b being strict inverses, the equality must be (for all a, b and c):

reflexive: a == a;
symmetric: a == b implies b == a; and
transitive: a == b and b == c implies a == c.
This property cannot be checked by the compiler, and therefore Eq implies PartialEq, and has no extra methods.

Mathematically speaking, there are times where you can define equality for most of the values in a type, but not all of them (floating point NaN's can't compare to anything). A lot of times even though the strict meaning of equality (represented as Eq) can't be used, it still makes sense to try and check whether two things are the same, returning a result that says either we could compare for equality (Some(true) and Some(false)) or we couldn't None.

I usually just derive PartialEq for my types if I want to be able to check whether they look the same using the == operator. However sometimes you need much stricter constraints, which is when you use Eq (e.g. keys in a hash map).

This PartialEq vs Eq difference is one of the things which help prevent the issues in javascript when sorting arrays which contain NaN or null.

3 Likes

So, if I don't want to all fields be same, should I impl the Eq by myself? or just impl PartialEq?

Eq can be thought of as a marker trait, kind of like Send and Sync. It's a type-level assertion that the type it's implemented for provides total equivalence. It doesn't add any extra API.

If you don't want all fields to be considered during equality, you'll need to implement PartialEq by-hand. If you also want to assert that this type has total equivalence, you'll implement Eq for it.

2 Likes

Don't have total equivalance. So, I shouldn't impl Eq?
I impl it because std said: Note that the derive strategy requires all fields are Eq, which isn't always desired.

Right - don't impl Eq then.

If you're using derive (i.e. #[derive(PartialEq, Eq)] struct MyStruct) then it will require that all fields are Eq themselves; this makes sense because deriving these impls just delegates to every single field. For the whole struct to be derivable to Eq, all its underlying fields must be Eq.

Since you're not going to be deriving these anyway, it's not applicable.

I impl the Eq because PartialOrd reqiures Eq.
And actually I'm working on a fraction collection.
When compare begin, I don't want denominator be zero anymore. So I impl the PartialEq and PartialOrd.
But Eq has no API to impl and it is required by PartialOrd. So, I'm confusing about it.

So, should I just derive it in this case?

PartialOrd requires PartialEq - where do you see it requiring Eq?

Oh, maybe I mixed up everything.
Sorry.

This topic was automatically closed 7 days after the last reply. We invite you to open a new topic if you have further questions or comments.