4

In a Rust tutorial about memory layout of different types, it talks about trait objects. However, as it shows, the part of trait object that lives on the stack has constant size: one word for pointer to the value, and another word for the pointer to its vtable = 16 bytes on a 64-bit machine. Diagram showing the memory layout of trait objects (that holds a Vec)

My question is that why then do we require a reference to the trait object, if it has a fixed size? Does this "fat pointer" consisting of two words actually the reference, because that's inconsistent with how references work in all of other Rust, where it's just a thin pointer to some data. And I don't believe Rust would be unnecessarily hiding this detail and being inconsistent.

zombiesauce
  • 1,009
  • 1
  • 7
  • 22
  • 6
    `&dyn Trait` is the fat pointer (2 words). `dyn Trait` (without a reference) is not sized. Yes, Rust is "inconsistent" in the sense that both normal and fat pointers use `&`. See also the size of `&[u8]` vs the size of `&[u8; N]`. – justinas Oct 14 '21 at 15:25
  • That image does not constitute a complete example. That `w` is a mutable reference, of type `&mut dyn Write`, which is in fact `Sized`. What is not `Sized` is the underlying value, the type of which was erased as it was made into a trait object. – E_net4 Oct 14 '21 at 15:26
  • See also: https://stackoverflow.com/q/28044231 and https://stackoverflow.com/q/57754901 – E_net4 Oct 14 '21 at 15:27
  • 3
    `dyn Trait` refers to the actual object behind the data pointer, which can be of any size. (In this case it's 3 machine words because the implementor is a `Vec`.) When you put it behind a reference, you get the familiar object with the constant size, a pointer-pointer pair in case of trait object, or a pointer-length pair in case of slice. – user4815162342 Oct 14 '21 at 16:44

1 Answers1

-1

As I learned in the comments, Rust is, in-fact inconsistent in how it treats &, which depends on the context. For example, &dyn Trait and &[T] are fat pointers, but in general, &T will be a thin pointer.

zombiesauce
  • 1,009
  • 1
  • 7
  • 22
  • 3
    I don't agree with this answer. The size of thin and fat pointers are different, but it is known which of them is used at the compile time. And the size of `&dyn Trait` is always two words. The thing is `dyn Trait` is kinda virtual type. There is no layout for it in the memory because it is in two different locations in the memmory (vtable and data). But `&dyn Trait` is defined to be two pointers pointing to these two different memory location. – Özgür Murat Sağdıçoğlu Feb 17 '22 at 19:50
  • @OzgurMurat that's exactly what I said. What my comment implies is that '&' in Rust is not as in C/C++, in which it is simply the addressof operator. Here, '&' by alone doesn't mean anything, what it is being applied on needs to be known as well. Coming from C++, I had the misconception that it must be one word long, but obv dynamic dispatch would require two words, hence my confusion. – zombiesauce Feb 19 '22 at 16:19
  • I mean, the reason of why you require reference to trait objects is not the same as to why other DSTs require references. Trait objects doesn't have size because there are no trait objects. They are only conceptual things. Only Trait object pointer exists, and it is not a pointer but two pointers pointing to different regions of memory (therefore we can't talk about an object). – Özgür Murat Sağdıçoğlu Feb 19 '22 at 17:28
  • 1
    @OzgurMurat yes, precisely the fact that reference to trait objects has a different semantical meaning than a reference to a traditional struct/data, yet uses the same syntax caused the confusion to me. Thanks for putting it in better words than I could :) – zombiesauce Feb 22 '22 at 16:37