Clarification on the best practice regarding using Into<>?

I have found the set_body method of Hyper library accepts an argument of type Into<B>, where B is Body.

I understand that Into is used here because From can not be defined by the Hyper for all possible known types in advance. But I am still not convinced that even Into is necessary after all.

What is the motivation behind doing this? Would not it be better for a client to do explicit conversion to the right type expected by a library instead of a library calling into() inside?

If we declare that using Into is the best practice, why would not we use this pattern everywhere?

It’s mostly to make callers more ergonomic. A better example is APIs that take AsRef<Path> - this allows callers to use strings, string slices, OsStr, Path, PathBuf and whatever else implements that trait. The caller can do the conversion themselves of course but this adds noise to all the callsites. Similarly, taking Into<B> allows caller to pass different types that can convert into B without conversion noise.

The major downside is code bloat - every invocation of the method with a different type causes specialization for that type to be generated (monomorphization). This is good in that compiler can optimize better but it can lead to lots of versions of the method being generated in the machine code. Consider also that this cascades - if you continue to call generic methods in the chain, they’ll also get specialized versions. This also increases compilation time. A common technique to combat that is to provide a public API that exposes the generic function, but then use the underlying type internally from there on out (this is best illustrated with the AsRef<Path> example).

The second downside is generics-heavy code is harder to read and understand, on average.

1 Like

Thanks. I understand the trade-offs.