The derived correctness of marker trait is not checked by compiler

I find out that derived correctness is only checked when using the trait(call the required method). However, marker trait like Eq doesn't have its own required method. So that the compiler won't check the derived correctness of marker trait and this correctness can only be ensured by programmer?

Example like this. Is there any way to help compiler to check it?

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Complex<T> { re: T, im: T }

fn main() {
    let v = Complex::<f32> {
        re: f32::NAN,
        im: 1.1,
    };
    println!("{}", v == v);
}

The Eq trait is not implemented for f32. Therefore this code snippet outputs false for NAN != NAN.

#[derive(Eq) there creates an impl<T> Eq for Complex<T> where T: Eq. Complex<f32> does not implement Eq, but does implement PartialEq, which is what == uses.

1 Like

I have implemented Eq for Complex<T>. So if Eq can not be implemented for Complex<f32>, there should be a compile error?

If by "check" you mean "I should get a compile error if I try to create a Complex<T> where Eq couldn't be derived", you would need to add the bounds you wanted to act this way to the type parameter. For example the bound below prevents the creation of Complex<f32>.

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Complex<T: Eq> { re: T, im: T }
//             ^^^^^

But this generally isn't recommended as you will have to repeat that bound whenever you do something generic with the struct.

impl<T: Eq> Complex<T> { ... }

More typically you'd just assert the bound (or Complex<T>: Eq) where it matters.


If you meant there should only be PartialEq if there's Eq, bulit-in derive can't help, you'll have to write it yourself.

impl<T: Eq> Eq for Complex<T> {}
impl<T: Eq> PartialEq for Complex<T> {
    fn eq(&self, rhs: &Complex<T>) -> bool {
        self.re.eq(&rhs.re) && self.im.eq(&rhs.im)
    }
}

If by "check" you meant "check that the PartialEq matches the intentions of Eq", there is no way to do that in the general case. Hence this part of the docs:

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

Violating this property is a logic error. The behavior resulting from a logic error is not specified, but users of the trait must ensure that such logic errors do not result in undefined behavior. This means that unsafe code must not rely on the correctness of these methods.

(The last paragraph is necessary as Eq is not an unsafe trait.)


If you meant something else, I'm not sure what you meant.

Not unconditionally -- read @sfackler's reply again and note the where T: Eq part. That's how the build-in derive works.

2 Likes

If by "check" you meant "check that the PartialEq matches the intentions of Eq ", there is no way to do that in the general case. Hence this part of the docs:

I think that is the real answer. Thank you.

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.