Rust wants me to add Sized constraint, but why

In the given example Bar implements Foo and cannot be instantiated, but Rust requires me to add a Sized constraint to the Foo trait. Why?
I would understand if it would require me to have such a constraint to FooInput because it is actually instantiated in code, but I do not get why it is needed for Foo.

trait FooInput {
	fn parse() -> Self;
}

trait Foo /*: Sized*/ { // uncomment `: Sized` to fix compilation error
	type Input: FooInput;

	fn run() {
		let _input = get_input::<Self>();
		//the size for values of type `Self` cannot be known at compilation time doesn't have a size known at compile-time
	}
}

fn get_input<T: Foo>() -> <T as Foo>::Input {
	T::Input::parse()
}


type BarInput = u32;
impl FooInput for BarInput {
	fn parse() -> Self {
		100
	}
}

pub struct Bar;
impl Foo for Bar {
	type Input = BarInput;
}

fn main() {
	Bar::run()
}

When you write this:

fn get_input<T: Foo>() -> <T as Foo>::Input {
	T::Input::parse()
}

That's short-hand for this:

fn get_input<T: Foo + Sized>() -> <T as Foo>::Input {
	T::Input::parse()
}

So to call it from run, you must know that Self is Sized. Another way you could get it to compile is this:

trait Foo {
	type Input: FooInput;

	fn run()
	where
	    Self: Sized,
	{
		let _input = get_input::<Self>();
	}
}

This lets you implement Foo on non-sized things, but only the things that are sized have to implement run.

Another way you can fix it is to remove the implicit Sized bound on get_input like this:

fn get_input<T: Foo + ?Sized>() -> <T as Foo>::Input {
	T::Input::parse()
}

The reason that it comes with a Sized bound by default is that function generics are typically an argument to the function, and function arguments must be Sized, so its convenient to require it by default.

5 Likes

So, that is because there is implicit Sized on every type parameter. Thank you.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.