I am pretty sure that this could work but I haven't figuered out how to implement it. Maybe one of you can lead me in the rigtht direction.
The Problem
I want to manage some objects that are hold by some kind of World. This struct has a Vec<Arc<Mutex<Box<dyn Trait>>>>. The World's task is to hand out Arcs to worker threads that depend on these Trait-objects. However, some threads require the concrete struct behind the trait-objects.
As far as I know, it is currently not possible to downcast a trait-object to its struct but this is not exactly my problem. The trait-objects are created together with the threads that require the concrete structs. My problem is how do I manage that one thread refers to Arc<Mutex<Box<TraitImpl>>> and hand an Arc::clone() of that as Arc<Mutex<Box<dyn Trait>>> to the World?
Yeah, there's some limited support for downcasting if you use Any, e.g. Box<Any>.
I don't think you'll be able to do this because Box<TraitImpl> and Box<dyn Trait> have a different representation (layout). In theory, a Mutex shouldn't care whether it's holding a Box<TraitImpl> or Box<dyn Trait + Send>, but we'd need machinery to allow such an unsized coercion via Mutex. I also may be overlooking something as I've not thought too deeply about this ...
At any rate, a typical way to allow downcasting like this is to put the downcast operation straight into the trait, e.g.:
Can you get rid of the inner Box in any way? I haven't tested it, but I'm 95% sure Arc<Mutex<TraitImpl>> can be coerced to Arc<Mutex<dyn Trait>>. The Box doesn't seem like it should be necessary.
this is what I've done meanwhile. I realized that there will never be more than two impls of the trait and switched to an enum.
Sometimes it is hard to get rid of this OOP-thinking of using dynamic dispatch everywhere.
Oh, indeed that's a good thought. For some reason, I thought the Mutex inside the Arc would preclude the unsizing but Mutex does allow T: ?Sized. So that "machinery" I alluded to is already present for this case.
Yeah, Rust enums are, IMO, one of its best features . Your case can be made to work, given the rest of the discussion in this thread, but I personally avoid trait objects as much as possible as sooner or later you hit some issues with them, mostly dependent on the type of trait though (i.e. generic lifetime param or not, associated type or not, etc).