Difference between bounds inside a where clause and "inline" bounds

Consider the example:

fn where_clause<T, F>(mut f: F)
where
    F: FnMut(&T),
{
        
}

fn inline<T>(mut f: FnMut(&T)) {
        
}

where_clause() is compiled well, why inline() gives the error:

warning: trait objects without an explicit `dyn` are deprecated

Adding dyn leads to the:

error[E0277]: the size for values of type `(dyn for<'r> FnMut(&'r T) + 'static)` cannot be known at compilation time

Could you please explain this difference?

The difference is that the first is using the trait as a trait, and the second is using it as a type. When you use a trait as a trait, the compiler will generate separate versions of the function for every choice of types you call it with. When you use it as a type, a single version of the function is compiled that can accept any value of any type that implements the trait.

When traits are used like types, they become something called a trait object, which is a specific type. The trait object type is not the same as the underlying trait that it corresponds to as traits and types are different things.

The reason it failed is that the trait object types can only exist behind a pointer because they could have any size. There could be a type of size one million bytes that implement the trait, and that type has to be supported. Supporting this only works if the value is behind a reference.

You may be looking for this syntax:

fn inline<T>(mut f: impl FnMut(&T)) {
        
}

The impl Trait syntax is a short-hand for generics, and this is equivalent to the first version.

2 Likes

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.