The Any
trait has two methods to take immutable and mutable references of downcast_ref
and downcast_mut. These functions use the
downcast_ref_uncheckedfunction under the hood and its implementation seems to be pure computation of pointers. I feel like we can remove the
Sized` trait bound from these functions. What do you think?
How do you propose the fat pointer be constructed?
The cast *const dyn Any
to *const T
is not valid if T
is not Sized
.
in addition to what's already said, you cannot coerce unsized types such as str
into dyn Any
in the first place anyway, it makes no sense for downcast_ref()
to support unsized types.
here's a paragraph from the documentation of Unsize
(with added emphasis):
A type implements
Unsize<dyn Trait + 'a>
if all of these conditions are met:
- The type implements
Trait
.Trait
is dyn-compatible- The type is sized.
- The type outlives
'a
Expanding a bit, this is a consequence of how Rust's unsized types are implemented: Their size information is stored as an extra field of the pointer itself, making it a pointer-length pair (for slices) or a pointer-vtable pair (for trait objects). To convert a str
or other slice into a trait object, you would need to store the length somewhere in order to prevent out-of-bounds accesses but there's no place to do that:
- It can't go beside the slice data, because it might be a subslice of something else
- It can't go in the vtable, because that's statically allocated and shared across multiple instances of the same type
- It can't be an additional extra field on the pointer, because then the pointer itself becomes unsized (because you can potentially continue this recursively as many times as you want)
Thank you for the very quick responses, everyone! I totally forgot and never thought about fat pointers with vtables. Thank you also for the detailed descriptions.
you cannot coerce unsized types such as
str
intodyn Any
in the first place anyway
To convert a
str
or other slice into a trait object, you would need to store the length somewhere in order to prevent out-of-bounds accesses but there's no place to do that:
I didn't know this at all. I thought that the upcast was at least possible.
I'm gonna just use some owned representation of data for these types not sized in my project then.
dyn Trait
s themselves are actually Unsize<dyn Trait>
(for any upcastable target), yeah.
But the way that Any
works is that if I type erase coerce ()
, these all call ()
's type_id
method...
dyn Any + Send + Sync
dyn Any + Send
dyn Any + Sync
dyn Any
...and the same is true of subtraits of Any
too. And upcasting doesn't change this.