std::cmp::PartialEq
states “that the trait itself must be implemented symmetrically and transitively: if T: PartialEq<U>
and U: PartialEq<V>
then U: PartialEq<T>
…” (emphasis added), but this is not actually enforced in its definition. I am sure I am missing something obvious, so can someone enlighten me as to why RHS
doesn’t have the trait bound std::cmp::PartialEq<Self>
in addition to its ?Sized
bound?
Why isn’t there an std::cmp::PartialEq<Self> bound on the RHS type parameter in std::cmp::PartialEq?
Whenever I've tried to implement that sort of circular bound chain, it confused the trait solver and threw it into an infinite loop. Perhaps it's just a limitation of the current implementation, and will work in the future. Or maybe I was just unlucky.
Good question! I would have thought that we would be hitting a circular bound in that case, but
trait Trait<U : ?Sized + Trait<Self> = Self> {}
enum A {}
impl Trait for A {}
enum B {}
impl Trait<A> for B {}
impl Trait<B> for A {}
compiles just fine, even on rust 1.0.0.
EDIT: yeah, the problem lies on the ergonomics of somebody using that generic bound: the constraint is seen to be required everywhere, instead of required on impl but assumed on use (like supertraits do). That is, having a <T, U : Trait<T>>
generic fails with the missing T : Trait<U>
bound.
This means that every (non-reflexive) usage of that bound would have ended up duplicated... which seems too cumbersome to be worth it.
I can be rather masochistic when it comes to “correctness” and fail to care about ergonomics as much as I should. I am working on that. Thank you for your reply.
P. S. Not really related, but I recently stumbled on one of your questions that I found to be useful as I was confused as to when one should favor supertraits over generic implementations.
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.