&Rc<Cat> to &Rc<dyn Animal>

pub struct Cat {}

pub trait Animal {}

impl Animal for Cat {}

fn good(c: Rc<Cat>) -> Rc<dyn Animal> {
    c
}

fn bad(c: &Rc<Cat>) -> &Rc<dyn Animal> {
    c
}

Why is it that good: Rc<Cat> -> Rc<dyn Animal> compiles, but bad: &Rc<Cat> -> &Rc<dyn Animal> does not compile?

Rc<Cat> and Rc<Animal> is completely different types, they even differ in size - Rc<Cat> has same size as a ptr, while Rc<Animal> has size of two ptrs. So it's something like to getting &u64 from the &u32. Of course you can convert u32 into u64, but to make &u64 someone else should hold this 8-byte-wide type. But all we have is the &u32, a reference to the 4-byte-wide type.

2 Likes

I'm completely lost now. When we do:

good: Rc<Cat> -> Rc<Animal>

are we (1) keeping the same "ref count counter object", or are we (2) decrementing the first counter by 1, and creating a new counter object with counter 1 ?

I used to believe (1), but am now considering (2).

It's (1), but the Rc<dyn Animal> needs to store an address to the vtable of the trait object dyn Animal next to the refcounted pointer.

1 Like

Basically the issue is that the conversion requires updating how the handle is stored, and to return a reference, you need somewhere to put that new handle, but you can't use the reference you got as it cannot be modified, and you can't return it either because that would be a return by value.

2 Likes