I can't understand why there is a conflict in playground.
The code is a conversion from Point to Vector and back.
These implementations conflict:
impl<AP, AV> Of<AP> for AV
where
AP: AnyPoint,
AV: AnyVector,
Vector: Of<AP>,
AV: Of<Vector>,
{
fn of(point: AP) -> Self {
point.to::<Vector>().to()
}
}
impl<AV, AP> Of<AV> for AP
where
AV: AnyVector,
AP: AnyPoint,
Point: Of<AV>,
AP: Of<Point>,
{
fn of(vec: AV) -> Self {
vec.to::<Point>().to()
}
}
I can't understand why, since they are constrained differently. AP is any point, that is, the AnyPoint trait is only implemented for &Point, Rc<Point>, &Rc<Point>. AV is any vector, so the AnyVector trait is implemented only for &Vector, Rc<Vector>, &Rc<Vector>.
So there should be no conflict because AV cannot be AP and AP cannot be AV.
I don't know what the problem is, if everything works in other cases, the orphan rule is observed and there are no overlaps.
Correction: the trait is only implemented for those right now.
The Rust coherence rules are setup to ensure that adding more in the future wouldn't cause overlaps, not just to look at the exact set that exists right now.
Hopefully we'll get negative impls (like impl !AnyPoint for &Vector) to promise that certain things won't ever be implemented, or specific dedicated support for sealed traits to allow tweaking the rules slightly in certain cases. But those don't exist in stable right now.
This is understandable, but why isn't rust made to give an error as soon as I implement a type?
Many specific cases rust detects itself before reporting an error, but with traits for some reason it doesn't.
I like the concept of traits, but it's frustrating that I can't fully utilise it.
I think for those two implementations you'd need full blown mutually exclusive traits with coherence support / trait solving support. In general today, if you have more than one blanket implementation, they will conflict with another.
I don't think that's changing any time soon, so on a practical level: Have something like
impl<AV, AP> Of<AP> for AV where AP: AnyPoint, AV: AnyVector {}
// Perhaps write a macro for these
impl<AV> Of<AV> for &Point where AV: AnyVector {}
impl<AV> Of<AV> for Rc<Point> where AV: AnyVector {}
impl<AV> Of<AV> for &Rc<Point> where AV: AnyVector {}
...is a breaking change. We decided that adding extra trait impls on existing types is not a breaking change, which means it shouldn't give error to downstream projects when you do so.
Could such a change affect project compatibility?
If Rust shows an error not based on the actual situation, but assuming that at some point a constraining trait will be implemented for a type that conflicts with another implementation, then there should not be such implementations in current projects where "assumed" conflicts are possible.
So, if changes are made in Rust to specifically consider each implementation and only then determine a conflict, this will not affect current projects because "assumed" conflicts were not implemented in them, which means specific conflicts as well.
If I understood you correctly.