But it seems the following code compiles without any complaints:
trait Foo {
fn foo(&self, a: Self) -> Self;
}
I suppose in this case, Self is sized by default. My question is, why am I required to explicitly specify sizedness in the first case and not the second?
StructA<T> probably contains a T, and also requires it to be sized (this is default bound on struct parameters.) By putting a Sized bound on the trait, you guarantee that this is satisfied for that method.
In the last case, you have no StructA, so it is not constraining anything. You can't pass in a Self to Foo unless it is Sized, so that method would simply be unavailable if Self is not Sized, and you'd get an error trying to call it if so. (This also means that Foo is not object safe)
The allowed form is a situation where well-formedness is not enforced at the declaration:
// Fine to declare it this way
trait Foo {
// But this isn't actually bound by `Sized`, even though you can't
// implement it unless sized. The bound is checked if you try to
// implement it.
fn foo(&self, a: Self) -> Self;
}
But the implicit type parameter bound for StructA<Self>is checked. If you change its declaration to StructA<T: ?Sized>, you can get it to compile-but-can't-implement status again.
Why is one lazy and the other not? I don't know.
Instead of putting the bound on the trait (or removing the bound from the struct), you can put it on individual methods:
FWIW, this is intentional, as we still aim to allow DST moves at some point (or at least I do).
I.e. it's fine to declare and doesn't have the bound because maybe some day it will also be possible to implement. But today it is not, so you get the error when you try to implement. (StructA<T> on the other hand is bound, implicitly, unless you opt out.)