Sized?, the position of type definition for a function parameter [Solved]


I have three functions with different styles of declarations. The first one doesn’t compile.

fn basename0(path: AsRef<std::path::Path>) {}
fn basename1<P: AsRef<std::path::Path>>(path: P) {}
fn basename2<P>(path: P) where P: AsRef<std::path::Path> {}

The compiler complains the parameter of function basename0 has to be Sized. This makes sense, since functions pass arguments by value. But why defining the type of the parameter in advance avoids such compiler error?

error[E0277]: the trait bound `std::convert::AsRef<std::path::Path> + 'static: std::marker::Sized` is not satisfied
  --> src/
33 | fn basename0(path: AsRef<std::path::Path>, sep: char) {}
   |              ^^^^ `std::convert::AsRef<std::path::Path> + 'static` does not have a constant size known at compile-time
   = help: the trait `std::marker::Sized` is not implemented for `std::convert::AsRef<std::path::Path> + 'static`
   = note: all local variables must have a statically known size


Trait objects are not Sized, because the many types that may implement that trait could all have different sizes. A single function ABI can’t deal with that, but you could write basename0 with a trait object reference like:

fn basename0(path: &AsRef<std::path::Path>) {}

Your generic examples will be resolved to some specific type P, and that type must still be Sized to be a parameter.


The first one is a single function that supports all types via dynamic dispatch (it would be an Interface in other languages).

The other kind is a static dispatch, which creates a new single-type function for every type you use it with (it would be a template in other languages).



Thank you so much! Lesson learned :grinning:


This is a good motivating example of confusion for the new dyn Trait RFC :slight_smile: