I have read about dyn
compatibility, "object safety", "trait objects" in the Rust reference, Rust book, etc. However, I'm confused about why we can't use a trait, bound with Sized
constrain like in the following example.
trait MyTrait : Sized {
}
struct MyStruct;
impl MyTrait for MyStruct{}
fn my_method(obj: &dyn MyTrait){
}
fn main() {
my_method(&MyStruct);
}
This code does not compile because only sized types allow to implement MyTrait
. This part is clear to me.
Next, let me break &dyn MyTrait
into pieces to be sure I interpret it correctly. As far as I know &dyn MyTrait
means "a reference to a value that implements the trait MyTrait
" which is widely know as a trait object. I also understand that a trait object is roughly represented like follows:
pub struct TraitObject {
pub data: *mut (),
pub vtable: *mut (),
}
A trait object is a mechanism to implement dynamic dispatch (or polymorphism). So, when we write a method like
fn my_method(obj: &dyn MyTrait){
}
we basically say "Hey Rust! we are going to pass a reference to some value that implements MyTrait
but whose concrete type is unknown at compile time". The type might be u16
, String
, &str
, or even custom MyCoolType
.
According to the trait object representation the size of the value is not relevant when we are tossing a trait object around.
So, this is what I don't understand: how does "being Sized
" prevent implementation of dynamic dispatch?
Yes, we cannot implement MyTrait
for str
, but why should it prevent passing Sized
types as trait objects? Maybe I want to pass only Sized
types? After all, Rust does not care about sizes which may be know or unknown at compile time.
Why is NOT possible to create vtables for only sized types? After all, if we might pass any value of any size, this also could be classified as "unknown size" at compile time: 2 bytes, 10 bytes, maybe 1Kb? The type will be known at run time.
could anyone clarify it?