Casting Reference of potentially unsized type to &Any

The following code results in a compiler error:

use std::any::Any;
fn demo<T: Any + ?Sized>(a: &T) {
    let b = a as &dyn Any;
}

&T
the size for values of type T cannot be known at compilation time
doesn't have a size known at compile-time
help: the trait std::marker::Sized is not implemented for T

Without the + ?Sized it works as expected. Can anyone explain the reason for this restriction?

The &dyn Any will need to store a vtable for the Any trait in its metadata, so where would the metadata from the original &T go?

Notice you can do let b = (&a) as &dyn Any; (which would need to be downcast as &T rather than T). In that case, you basically have two layers of metadata. (pointer with Any vtable to pointer with original meta)

2 Likes

Thank you for your immediate response! Unfortunatelly I don't understand the problem yet.
I thought, that vtable is only pointing to the trait implementations for dynamic dispatch?
Why is it relevant wether the underlying type has a size or not? :-S

Is it not possible in the current implementation or is it conceptually impossible?
I tried your code but if I just replace the function body with your code, there is another compiler error that i have difficulties to reason about:

a: &T
explicit lifetime required in the type of a
lifetime 'static requiredrustc(E0621)

The passed references should't be restricted to static ones...

@ExpHP Is it even possible to construct a &dyn Any from any unsized type at all?

No, you can only convert Sized types to trait objects.

1 Like

Because dynamically-sized types also need the same one usize worth of metadata for storing their own size. If the size of a value is not known statically, it must be known dynamically, otherwise it would be impossible to do anything sound with it.

Thank you for pointing out that only sized types can be converted. I marked your answer as the solution. If anybody wants a simple example to verify that you can run the following snippet:

#[test]
fn caller() {
    let a = "test";
    callee(a); // err: the size for values of type `str` cannot be known at compilation time
}

fn callee(a: &dyn Debug) {
}

I was still confused as I expected references to unsized types to have the same size as a normal reference. Maybe these lines help someone else too. Thank you for your support!

assert_eq!(
    std::mem::size_of::<&i32>(), 
    std::mem::size_of::<usize>()
);
assert_eq!(
    std::mem::size_of::<&dyn Debug>(),
    2 * std::mem::size_of::<usize>()            
);
assert_eq!(
    std::mem::size_of::<&[i32]>(),
    2 * std::mem::size_of::<usize>()
);
1 Like