Trait object with generic parameter

A specific case for the well known problem, that I can't solve.
In my case, the trait has a function with a parameter of a generic type that is fully specified.
See playground:

I have read:

but I can't find how to apply it to my case.

I don't have solid knowledge about this, but here is my guess.

When you are calling functions via "dyn Trait", what are you doing is calling function via v-table. However generic function is not an actual function, it is the "famili of functions". The problem is, that the actual functions are generated by compiler only if they are called. It is like "template for generating the function" (very similar concept to C++ templates).

The result of this is, that there is impossible to create a v-table for the trait containing generic functions. The reason is, that the generic function is actually infinite number of functions (it would be needed to create v-table entry for any possible type, which sometimes could be actually infinite number of types - in case of recursive types). The solutions are: not allow to create trait objects from trait with generics functions, or not allow to call generic functions on trait objects. It seems, like Rust went the first way (I would pick it too).

Solution - just change your &mut impl Drawing<W> to &mut dyn Drawing<W> so there is actually one function - taking fat pointer to some trait, and this would work. Downside: you would have more dynamic dispatch, which costs. However my opinion here is, that this is not a problem - you are considering some drawing stuff, probably the v-call has ommitable cost.

2 Likes

Thanks, that's a step forward :slight_smile:
Now Drawing cannot be made into an object - I have added a generic function there, to reflect actual case:

You are right about the vcall, it's not a problem in my case.

The problem is exactly the same as in previous case. You have the trait Drawing<T> trait, with the generic method fn draw<C>(&mut self, item: C). Because Drawing has a generic method, no matter if introduced via impl Trait or straight via generic type, it cannot be turned into trait object. Actually the draw function could be also defined as fn draw(&mut self, item: impl Sized).

Also the draw function is pretty much useless - you cannot do almost anything with the item in implementation, because the only behavior it guarantees is... being sized. If you really need another level of indirection (the C type), give it some trait (like Draw with some function) and go with additional v-call, like fn draw(&mut self, item: &dyn Draw), or if you want this to take ownership: fn draw(&mut self, item: Box<dyn Draw>). TBH it is not so simple to propose best solution, because I don't know where are you going exactly with this implementation - it seems like some GUI rendering, but it seems already a little to complicated in terms of indirection layers.

Thanks, I had to simplify the code to isolate the issue so I guess it seems a bit pointless.
Anyway, I've figured what I wanted to do is too complex (or even impossible) within the boundaries (e.g. can't change Drawing as it's from an external crate). I will approach the problem from an entirely different angle.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.