How do I cast Box<dyn Foo> to Box<dyn Bar> properly?

In rust, can I cast a dyn trait to another dyn trait? For example:

use std::mem::transmute;

trait Foo {
    fn echo(&self) {
        println!("Foo")
    }
}
trait Bar {
    fn echo(&self) {
        println!("Bar")
    }
}

struct Baz {}

impl Foo for Baz {}
impl Bar for Baz {}


fn main() {
    let f : Box<dyn Foo> = Box::new(Baz {});
    let b : Box<dyn Bar> = unsafe {transmute(f)};
    b.echo();

}

The result still print "Foo", which is not what I intended to. So (how) can I cast dyn trait from one two another? Both safe and unsafe way is accepted.

Casting Box<dyn Foo> to Box<dyn Bar> in your example would be unsound since it's not guaranteed that every type that implements Foo also implements Bar. A better example would be

trait Bar {}
// anything that implements Foo must also implement Bar
trait Foo: Bar {}
fn upcast(x: Box<dyn Foo>) -> Box<dyn Bar> {
    todo!()
}

This is not directly supported by current Rust (including nightly), although there is a desire to support it.

Since these traits have no relation to each other (Rust's type system is nominal, not structural), you can't cast between them directly. You have to downcast back to the underlying concrete type.

In the example I may know what is the downcast type, but in my real case, I don't know, do you know any hack or feature or code design(such as adding more meta data) to accomplish this? This is really important to me now...

It's not accurate that "I don't know the down cast type", I create structs, but just not that ovbverslly I can know what's the type when comming to the boxing cast part...

No, you can't cast between unrelated traits without knowing what concrete type implements them both. If you know that trait 1 always implies trait 2, then you can upcast from trait 1 to trait 2 (but not in the reverse direction!) by essentially implementing the upcasting mechanism yourself, like this.

3 Likes

Note that when implementing upcasting yourself as @H2CO3 suggested, you can avoid the need of having to repeat the definition of an upcast method for each type that implements the trait, by introducing an additional trait in the hierarchy that has a generic implementation, e.g. like this.

2 Likes

Thanks guys, but it seems that I do need down casting, something like dyn_cast in C++... I know that it's probably not a feature in Rust, but do you have any idea on how to write codes to accomplish this work, no matter how complicated it is?

P.S. Currently what I got:
every type which need to be cast between dyn types has a type id.

P.P.S If you are curious what I'm doing, I'm writing a serialization crate, and I want to support reading some bytes, depend on the type id(which is encoded in the bytes as well), to turn a struct which implements Foo to turn to a box<dyn Foo>

C++ doesn't have traits; downcasting using dynamic_cast converts between concrete types (superclass to subclass). However, subtying doesn't exist in Rust between traits (technically, subtyping does exist in terms of lifetimes, but that's not helpful here).

This means that:

  • Either you do know the concrete types, and you are switching on the type ID, in which case you can work with the "upcast to concrete type" solution;
  • Or you are trying to summon concrete types from the void, which is simply not possible. You can't dynamically create concrete types in Rust, and you can't access a compile-time type based on a runtime type ID.
1 Like

Thanks very much, there are some new concepts for me here, I need to think about it for a while...

I just found that there’s a crate typetag - Rust that does serialization of trait objects. You didn’t give much detail about your concrete use-case so I don’t know if it could be useful.

3 Likes

It seems that it does exactly what I want :star_struck:, I'll investigate the implementation details.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.