In Python, all values have a uniform representation*, and distinguishing between subtypes is always done at run time. The same is not true in Rust; though a Box<dyn Anime>
can be converted into a Box<dyn Media>
, they are represented differently. (This would be more obvious if Media had its own methods, like fn title(&self)
. In that case, watch_media
might expect to be able to access the title method directly, but the representation of Box<dyn Anime>
would only provide it behind a second layer of indirection. You can learn more about the representation of trait objects in Trait object types - The Rust Reference )
Now, the compiler could actually go a step further and insert this conversion for you! However, it can only cheaply do so in cases like this, where the function being passed is concrete. If you’re instead forwarding from one impl Fn
to another, the conversion layer would have to capture the original function like a closure does, which would shorten its lifetime. So, at least for today, the language requires you to write the closure explicitly, giving a home for the code that does the upcasting.
* This is a polite fiction, the value representation for most Python interpreters is more like a carefully-constructed union or checked enum. But it’s still true that distinguishing types is done at run time.