I want to compare Obj
s 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?
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.
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.
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 .
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.
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>
.
X <: Y
=> G<X> <: G<Y>
X == Y
=> G<X> <: G<Y>
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!!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With