I'm currently writing a really stupid project (write a python AST in json and this magical transpiler thingy majigy will turn it into python, what I'm writing), and I need to cast between different trait objects.
I currently have a Codegen trait that defines a code generation function, but I also have another ContainsBlock trait that extends then Codegen trait that defines a getter and a setter for how many indents deep the current code block is. I need to cast from a Box<dyn Codegen> into a Box<dyn ContainsBlock>, and so far I have not found a way of casting from the supertrait to the subtrait without it failing at runtime (Talking about std::any::Any, downcast_ref::<Box<dyn ContainsBlock>>() doesnt work).
Any ideas on how I can do that, or other ways I could implement this?
Rust doesn't support this. This is precisely why I try to discourage people from thinking of traits as like interfaces from Java or C#. (There's an RFC for this specific case (RFC 3324), but that hasn't been stabilised yet.)
About Any: downcasting only works to the single, specific concrete type that the dyn Any was created from. You can't downcast to trait objects, even if the underlying type implements those traits. The information needed for this to work simply doesn't exist at runtime.
The way I've solved this in the past is to ensure that any trait objects I need to cast have methods specifically for doing the cast manually. For example, let's say I have a collection of dyn Animals, and I need to be able to sometimes cast them to other trait objects. The trait might end up looking like this:
trait Animal: Object + fmt::Debug + Food {
// The functionality of `Animal`.
fn make_noise(&self);
// Trait casts.
fn as_debug(&self) -> &fmt::Debug;
fn as_display(&self) -> Option<&fmt::Display>;
fn as_object(&self) -> &dyn Object;
fn as_pet(&self) -> Option<&dyn Pet>;
// Maybe you need to do this, too?
fn into_food(self: Box<Self>) -> Box<dyn Food>;
}
The implementation of those as_* and into_* methods are usually trivially simple, but you do need to do them for every type that implements Animal.
There might be a good crate that can automate this to some degree, but I'm not personally aware of one.
Every problem can be solved with one more level of indirection! Just add a supertrait and a blanket impl for automatically implementing the as_trait_object() methods: Playground.
Here's a version with Boxes. I'm not convinced it's the best way, and hopefully I correctly avoided nested boxing and the like correctly. (Not tested beyond what you see.)
Unconditionally obviously not, but see my playground.
The core concept is getting to the compiler to implicitly and infallibly downcast to the concrete base type (as part of dynamic dispatch of self: Box<dyn Trait>) at which point its upcasting implementation will be called.