When you have a dyn-safe trait (e.g. io::Write), it's common practice to provide forwarding impls like impl<T: Trait + ?Sized> Trait for &mut T as possible given the method receivers. This means that you can write functions like fn f(out: impl Trait) once and use it for both monomorphic and dynamic dispatch, providing &mut dyn Trait for the generic parameter type.
There's a bit of a wrinkle when f wants to always use dynamic dispatch for some or all of its impl, though. When you do (&mut out) as &mut dyn Trait, you end up adding an additional extraneous layer of dynamic indirection for the extra syntax sugar of providing a monomorphic API around the internal dynamic dispatch.
Assuming the API can't just be written to directly use dyn Trait[1], what patterns do you use to avoid the accumulation of dyn indirection layers? The only option I can really think of is to add a method fn as_dyn(&mut self) -> &mut dyn Trait; unfortunately, this needs to be manually implemented by every trait impl if it's going to be provided by dyn Trait, as it's impossible to provide a default method body that will work for Self: ?Sized.
What I've ended up doing the couple times I ran into this was make the dyn Trait-taking API pub(crate) such that when higher-level batch API delegates to the lower level API it doesn't end up stacking more indirection beyond the first level unnecessarily.
One notable potential reason would be utilizing where Self: Sized functionality, or even just the ability to inline some generic setup around the core dynamically dispatched computation. Another is that the dyn trait is actually a supertrait, with the generic API taking a non-dyn-safe subtrait. ↩︎
If you change a function from taking impl Trait by ownership to instead always take a mutable reference, then you can often avoid creating additional dyn references on each call.
I believe you can avoid having to implement it if you put it on a helper trait Helper such that Helper is blanket implemented for any T: Trait and Helper is a supertrait of Trait.
I second this. It's useful in many dyn scenarios where you want a default body for T: Sized and want the compiler to supply the implementation for dyn Trait. Here's a recent example.[1]
Ah yes, that's clever. And you can even hide this by making a Trait method default delegate to the Helper implementation. That probably isn't the best idea since impl library::Trait for dyn crate::Trait will expose the trickery, but it's definitely a cute trick.
Such that dyn DebugAny: AsAny. We have an implication from DebugAny + Sized to AsAny, but we need DebugAny + ?Sized to AsAny.
At least if you're putting the dyn through generic API. If you hit explicitly polymorphic API, to turn &mut impl Trait + ?Sized into &mut dyn Trait you need to add another reference, because you can't unsize an already unsized value.
Basically whenever you want a default body that requires Sized or some other non-dyn-capable bound, but you want the method to remain dyn-capable (so you can't add the bound to the method).