coherence versus generic traits in rust
There was a question in #rust-beginners a while back where someone was confused about how anyone
could write an impl for From
when an impl<T> From<T> for T
already existed. For the most
part, if you impl something for T
, then coherence rules generally enforce that no other specific
impls can exist, since they’d overlap with the generalized impl. (At least, until specialization
shakes itself out.)
Initially, I’d thought that it was the preliminary specialization work that had allowed people to
write their own From<SomeType> for OtherType
impls. My mental rule is just what I’d written above:
An impl for T
precludes any other specific impl. It turns out, though, that specialization has no
part in this; this rule’s been there the entire time, so it had to have worked before specialization
was a thing!
The proper way to think about it is that From<T>
isn’t really one trait. It’s a sort of trait
category, since T
could really be anything. So impl<T> From<T> for T
isn’t as broad as it seems.
The situations covered by this line only account for things like impl From<Thing> for Thing
, which
has a trivial and obvious implementation: Just pass the Thing
through.
So if you write a discrete From<SomeType> for OtherType
impl, it won’t clash with the generic impl
above, and everything works out. And since this is how the “one error enum to rule them all” pattern
works, it’s rather nice that this is available.
(This impl can still get in the way, though. If you want to write a generic impl<From, To>
From<From> for To
, regardless of what constraints you put on, it will clash with the above impl,
since - in Rust 1.14, at least - you can’t specify that From != To
. Until you can add that
constraint in, impls of this kind are off-limits, sadly.)