Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I compare objects only when they are created from the same parent object?

Tags:

rust

I want to compare Objs only when they are created from the same Parent object, and it works, but only one way: if you switch the order of comparison, it does not.

Here's the minimal code:

use std::marker::PhantomData;

struct Parent {
    val: u64,
}

impl Parent {
    pub fn new(v: u64) -> Parent {
        Parent { val: v }
    }

    pub fn child(&self, v: u64) -> Child {
        Child {
            val: v,
            phantom: PhantomData,
        }
    }
}

struct Child<'a> {
    val: u64,
    phantom: PhantomData<&'a Parent>,
}

impl<'a> Child<'a> {
    pub fn compare(&'a self, l: &Obj<'a>, r: &Obj<'a>) -> bool {
        l.val == r.val
    }

    pub fn obj(&'a self, v: u64) -> Obj<'a> {
        Obj {
            val: v,
            child: self,
        }
    }
}

struct Obj<'a> {
    val: u64,
    child: &'a Child<'a>,
}

impl<'a> PartialEq<Obj<'a>> for Obj<'a> {
    fn eq(&self, other: &Obj<'a>) -> bool {
        self.child.compare(self, other)
    }
}

#[test]
fn test() {
    let parent = Parent::new(1);
    let child = parent.child(2);
    let obj1 = child.obj(3);
    let obj2 = child.obj(3);

    // those are from the same parent, this sould work (and works).
    assert!(obj1 == obj2);
    assert!(obj2 == obj1);

    let parent2 = Parent::new(1);
    let child2 = parent2.child(2);
    let obj12 = child2.obj(3);
    let obj22 = child2.obj(3);

    // this works fine too
    assert!(obj12 == obj22);
    assert!(obj22 == obj12);

    // those are from different parents

    //assert!(obj1 == obj12); // that line DOES NOT compile, which is exactly what I want!
    assert!(obj12 == obj1); // but that line suddenly DOES compile.
}

How can I change the code so that the last line won't compile?

like image 559
monnoroch Avatar asked May 29 '15 12:05

monnoroch


People also ask

How do you compare two values of objects?

In Java, the == operator compares that two references are identical or not. Whereas the equals() method compares two objects. Objects are equal when they have the same state (usually comparing variables). Objects are identical when they share the class identity.

Can you compare two objects of the same class?

This can occur through simple assignment, as shown in the following example. Value equality means that two objects contain the same value or values. For primitive value types such as int or bool, tests for value equality are straightforward.

How do you compare two objects in the same class in Python?

The == operator compares the value or equality of two objects, whereas the Python is operator checks whether two variables point to the same object in memory. In the vast majority of cases, this means you should use the equality operators == and != , except when you're comparing to None .

How do you check if two objects are the same in Python?

The is keyword is used to test if two variables refer to the same object. The test returns True if the two objects are the same object. The test returns False if they are not the same object, even if the two objects are 100% equal. Use the == operator to test if two variables are equal.


1 Answers

I'll happily explain the lifetime approach, but it doesn't seem to be viable.

When is X a subtype of Y (denoted X <: Y)?

The question posed for generics involves variance.

The variance answers the question: for a generic type G<X>, what does X <: Y mean for the relation of G<X> to G<Y>.

  • Covariance: X <: Y => G<X> <: G<Y>
  • Invariance: X == Y => G<X> <: G<Y>
  • Contravariance: X <: Y => G<Y> <: G<X>

Cell<X> is invariant w.r.t X, so phantom: PhantomData<Cell<&'a Parent>>, makes Child<'a> invariant w.r.t 'a.

PhantomData is a way to trick you to talk about variance by just describing it in types you already know.

This appears to work, but not so fast, because we can create a situation where the lifetimes are totally equal, and then the test compiles again!

let (parent, parent2) = (Parent::new(1), Parent::new(1));
let (child, child2) = (parent.child(2), parent2.child(2));
// Plan is foiled!!
like image 108
bluss Avatar answered Dec 31 '22 19:12

bluss