@OptimisticPeach I think he was asking the opposite, why use (data, vtable) over dyn Trait, as is the case with the types he listed.
There are a few potential uses cases for this,
- To have a more compact representation of the
(data, vtable)pair as withtokio'sRawTask
RawTask is only 1 word in size, where as fat pointers that represent trait objects are 2 words.
- To allow dynamically generating parts of the process. (None of the above)
- To control the layout (
RawTask) - Other optimizations (
std::task::RawWaker)
With RawWaker we don't want to constrain what can be used to represent the waker, so we would like to efficiently type erase it. We have two options here, since we don't want the end product (Waker) to have any generics on it's interface:
- use trait objects
But there is a catch, it will require an allocation
pub trait RawWaker { ... }
pub struct Waker {
raw: Arc<dyn RawWaker + Send + Sync>
// /\ this allocation, pick your favorite smart pointer
}
This is unacceptable, because we want to support no_std futures in environments that don't have an allocator. So how do we fix this?
- roll out our own trait objects
This is what Rust went with, this way you need to supply a pointer to RawWaker and a RawWakerVTable which do all the same things as a normal data pointer and vtable, but with the added bonus of not having to deal with the allocation.
Normally in std applications we do allocate using an Arc, but Rust doesn't want to compramise on no_std futures. So we must use dirty tricks like this to get things working.