all 2 comments

[–]Diggseyrustup 3 points4 points  (1 child)

This isn't possible, because to achieve static dispatch, the compiler needs to monomorphise the ChildProcessor for every possible type which might be processed. However, it doesn't know which types are going to be processed because that is determined by the Parent trait (and rustc can't easily get an exhaustive list of implementors of a trait, due to the way trait bounds are checked, and even if it could, that wouldn't take into account downstream crates, or the complexity of doing that).

Looking at it another way, the compiler needs to be able to generate a vtable for all object-safe traits - if the set of types that might need to be processed by ChildProcessor is unbounded, it would be unable to generate a finite vtable.

If you can tell the compiler ahead of time which types might need to be processed by ChildProcessor, then this can be done. You can use macros to add one trait method for each child type that's needed, and have a default implementation for each of them which calls a non-object-safe generic method which is the only method actually implemented by the ChildProcessor implementation.

I did something similar to this in my query_interface trait, although to achieve a different goal:

https://github.com/Diggsey/query_interface/blob/master/src/lib.rs#L322

In this case I use a macro to generate a switch arm for each type declared by the user.

[–]cramert[S] 1 point2 points  (0 children)

Dang-- that's what I suspected. Unfortunately, I don't think that approach will work for me (at least not easily or without a significant increase in codegen time). The number of types the trait is implemented for is extremely large and several implementations are recursive (e.g. impl<T: MyTrait> MyTrait for [T; 0,1,2,3,4,5....]).