// trait
pub trait Serialize {
type Input;
}
// implementation for tuple
impl<T0, T1> Serialize for (T0, T1)
where
T0: Serialize<Input = <T0 as Archive>::Archived> {}
For this example imagine tuple is (u32,u32).
I implemented the primitives and their Input has already been defined.
I don't really get why I need to further constrain Serialize with <Input = <T0 as Archive>::Archived> since the compiler could find out by itself.
There is a bit I miss here (because otherwise it would work that way).
Could someone explain me ?
Is it because the compiler only reads the function declaration to make sure everything is ok (hence we need to give it as much info as possible in the declaration).
It helps with the compilation performance but it implies the dev writes more. Am I right ?
I need to understand the logic to comply with it.
What makes you think that the compiler can figure out Input = <T0 as Archive>::Archived? You haven't really provided any information about this Archive trait, so I can't tell where that information should come from.
It's because the implementation has to work for all types A and B that meet the bound -- including all possible future implementations, not just the current ones. So if you need to rely on some sort of type equality, you need to put it into the bound.
E.g. in that other thread, there's nothing preventing an implementation of Serialize where the associated Nominative type is not Self.
If you want some implementations for a fixed set of types, and want to rely on details of those implementations that aren't expressible as trait bounds,[1] sometimes macros to create a bunch of implementations on the specific types are a better approach than generic implementations.
Here is the playground. Careful, it's simplified to only show what bothers me. The Serialize trait is much fatter than this. and its serialize_value has been truncated of many of its parameters that are non essential to the issue.
@quinedot currently I am testing the whole crate, and it looks like it's working fine (finally!).
I need to absorb the knowledge here.
I think it clicked: to use the Serialization trait, I also have to define the associated type because I use it in the serialize_value. Without the full definition, it could be anything.
So, from now on, whenever I use (an) associated type(s) in a trait, I should provide the full constraint for them all the time.
That way, the habit is taken and no more question about it. Even if not explicitly needed, or if the compiler doesn't complain.
That should take me a long way. Fingers crossed.
Thanks anyway, that journey has been great. And it's only the beginning
fn chain<U>(self, other: U) -> Chain<Self, <U as IntoIterator>::IntoIter>
where
Self: Sized,
U: IntoIterator<Item = Self::Item>,
It contrains IntoIterator::Item for equality with Self::Item, as it needs to return the same item type for Chain's entire iteration across both sub-iterators. But it doesn't constrain IntoIterator::IntoIter, since it can work with any iterator over Self::Item.