Implement PartialEq for invariant type

I have a type a with an invariant lifetime. The trait ParitalEq requires that the both types have the same lifetime parameter. Since this is invariant, rust cannot unify the lifetimes. Therefore I can't compare objects with different lifetimes. Is there a way around this, or is this a fundamental limitation of the rust trait system?

playground link

use std::{cell::Cell, marker::PhantomData};

#[derive(Debug)]
struct Object<'invariant> {
    val: usize,
    marker: PhantomData<Cell<&'invariant ()>>,
}

impl<'invariant> std::cmp::PartialEq for Object<'invariant> {
    fn eq(&self, other: &Self) -> bool {
        self.val == other.val
    }
}

impl<'a, 'b> Object<'a> {
    fn eq(&self, other: &Object<'b>) -> bool {
        self.val == other.val
    }
}

fn make_object<'a>(s: &'a str) -> Object<'a> {
    Object {
        val: s.len(),
        marker: PhantomData,
    }
}

fn make_static_object(s: &'static str) -> Object<'static> {
    Object {
        val: s.len(),
        marker: PhantomData,
    }
}

fn main() {
    let outer = make_static_object("static string");

    {
        let inner_str = String::from("string");
        let inner = make_object(inner_str.as_str());

        // Error: std PartialEq does not work
        assert_ne!(outer, inner);
        // But custom eq implementation does
        assert!(!outer.eq(&inner));
    }
}

I just realized I can do this to solve the problem.

impl<'a, 'b> std::cmp::PartialEq<Object<'b>> for Object<'a> {
    fn eq(&self, other: &Object<'b>) -> bool {
        self.val == other.val
    }
}

PartialEq takes an optional parameter to specify the RHS type:

impl<'a, 'b> std::cmp::PartialEq<Object<'b>> for Object<'a> {
    fn eq(&self, other: &Object<'b>) -> bool {
        self.val == other.val
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=579ae5ff4838850c9078ed272c72cb6c

2 Likes