Cracking Open Rust's dyn Trait: A Hands-On Tour of Vtables and Wide Pointers
A developer coming to Rust from C++ dissects how the language implements polymorphism, contrasting static dispatch (generics/monomorphization) with dynamic dispatch (dyn Trait). With generics, the compiler stamps out a specialized copy of a function for each concrete type, yielding zero runtime overhead but requiring all types to be known at compile time — Rust’s cleaner answer to C++ patterns like virtual functions and CRTP. The key philosophical difference: C++ templates accept any type with a matching method implicitly, while Rust forces you to spell out the contract by implementing a trait.
The post digs into two memory-level surprises. First, empty structs are zero-sized types (ZSTs) that occupy no memory, because Rust tracks value identity through ownership and the borrow checker rather than through distinct addresses — a break from C++‘s rule that every object is at least one byte. Taking the address of a ZST appears to yield distinct locations in debug builds, but that’s just a debugger convenience; in release mode the addresses collapse, and the compiler guarantees nothing about them.
Second, dynamic dispatch via &dyn Trait produces a ‘wide pointer’ that is twice the size of an ordinary pointer (16 bytes vs 8 on 64-bit): one half points to the data, the other to a vtable that resolves which method to call at runtime. Using an unsafe transmute to peek at the raw pointers, the author shows that all instances of a given type share a single vtable while each instance carries its own data pointer. It’s a practical, memory-first walkthrough for engineers who need to see what’s actually happening under the hood before they trust the abstraction.
Read the full article
Continue reading at Hacker News →This is an AI-generated summary. Read the original for the full story.