rustupcastingdynamic-dispatch

Re-boxing trait objects to generically implemented trait


So far I have rarely had issues with Rust's type inference, but I fear I don't quite understand the problem with the following code:

trait SpecificTrait {}

struct SpecificStruct;

impl SpecificTrait for SpecificStruct {}

trait GeneralTrait {}

impl<T: SpecificTrait> GeneralTrait for T {}

fn new_specific_box() -> Box<dyn SpecificTrait> {
    Box::new(SpecificStruct {})
}

fn new_general_box(from_specific_box: bool) -> Box<dyn GeneralTrait> {
    if from_specific_box {
        new_specific_box()
    } else {
        Box::new(SpecificStruct {})
    }
}

Playground

I assume it has to do with Rust probably still not supporting upcasting, though in this code SpecificTrait does not require GeneralTrait, but rather implements the more general trait generically over all types that implement SpecificTrait.

I am aware that the trait object types are different (which leads to the error in the above code), but I would expect type inference to acknowledge that every dyn SpecificTrait object should also be expressable as a dyn GeneralTrait object. However, I also cannot simply cast a Box<dyn SpecificTrait> as Box<dyn GeneralTrait>, either.

So, how would I (idomatically) have to go about re-expressing my Box<dyn SpecificTrait> as a Box<dyn GeneralTrait>?


Solution

  • Another answer explained why you can't simply cast the trait object to get the result you want. However, there is a workaround:

    impl SpecificTrait for Box<dyn SpecificTrait>{}
    fn new_general_box(from_specific_box: bool) -> Box<dyn GeneralTrait> {
        if from_specific_box {
            Box::new(new_specific_box())
        } else {
            Box::new(SpecificStruct {})
        }
    }
    

    In words, simply implement your specific trait for a boxed trait object, then box that. Not the most efficient, but it will work.

    Playground