I'm building myself a parsing library, and I found a key distinction between two types of declared trait bounds.
Take the following trait:
pub trait Parsable: FromStr<Err: Display>
{}
With this, the following function compiles and works just fine:
fn parse<T>(s: &str) -> Result<T, T::Err>
where
T: Parsable
{
s.parse()
}
However, if the Parsable trait is declared in this way:
pub trait Parsable: FromStr
where
Self::Err: Display
{}
Then the above defined parse function fails to compile.
`<T as FromStr>::Err` doesn't implement `std::fmt::Display`
the trait `std::fmt::Display` is not implemented for `<T as FromStr>::Err`
You have to also explicitly constrain T::Err to Display within the declatation of parse like this:
fn parse<T>(s: &str) -> Result<T, T::Err>
where
T: Parsable,
T::Err: Display
{
s.parse()
}
And only now does it actually compile.
My question is - why? What is the semantic difference between the two trait declarations?