Returning Trait Objects

Written on 22 Jan 2020

This is a fairly basic Rust syntax issue that I’ve run into several times. Based on unknowable runtime conditions, I will return one of several different return types from the same function. Also, this return type must use methods from two traits. How can I express this in Rust?

For the return impl Trait syntax, the compiler will only allow us to return one concrete type.

Why Can There Be Only One?

I think there are two advantages if I understand this right:

Static dispatch and runtime performance improvements

More flexible public API contract for consumers of a library

It’s a middleground for library authors to avoid committing to a specific type in their public API without sacrificing the performance improvements of static dispatch. I think you might even be able to swap out the return type at compile time using cfg!() macros or what-not. Cool!

I have no idea why you can’t name multiple normal traits in a trait object. That’s why we have to make a super trait BoilerTrait that requires the traits you actually want.

Use Type Annotations for Temporaries

When trying something more complicated than the examples above, temporary values weren’t automatically recognized as the trait object I had in mind…It seems like the type inference could be better at this case, but in rust 1.40.0 you need explicit type annotations for this case.

The compiler complains that the conditional returns different types. This is confusing because, the exact same expressions were returned just fine a moment ago without the let binding.

In our previous examples, without the temporary, the final expression from the conditional is returned from the function, which is explicitly annotated as -> Box<dyn BoilerTrait> so the compiler doesn’t have to do any guessing about the type. However, it does have to guess about the type of temporary because there’s no type annotation when the value is bound. Once the compiler decided that temporary is going to be a concrete type, we’ve lost the trait object.