When reading the interface of join method for vec, i got a small question.
// https://doc.rust-lang.org/src/alloc/slice.rs.html#573-575
#[rustc_allow_incoherent_impl]
#[stable(feature = "rename_connect_to_join", since = "1.3.0")]
pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where
Self: Join<Separator>,
{
Join::join(self, sep)
}
The point i am quite confused is that the return type of the method is <Self as Join<Separator>>::Output. IMHO, the return can just be Join<Separator>::Output because in the following where clause there is already a bind about Self and Join i.e. Self: Join<Separator>.
No, you certainly can't write Join<Separator>::Output because Join<Separator> is a trait. Sure, we know that Self implements that trait, but there are also other things that implement it. The colon does not mean equality — it means "left-hand-side implements right-hand-side".
That said, writing Self::Output would be ok here. (Unless Self implements multiple different traits with an associated type called Output, as it would become ambiguous if there are several.)
Trait::Associated is considered ambiguous because in addition to <Self as Trait>::Associated, there are also other known candidates (<SomethingElse as Trait>::Associated).
The Self: Trait bound doesn't erase the knowledge that SomethingElse: Trait.
Self::Output would work in this case though. But it's still technically less robust as it would become ambiguous in the face of
impl<T: ?Sized> EverythingExt for T {
type Output = ();
}