I want extendable enum because I know that Trait object is slower then normal enums
And I saw that enum_dispatch shown that there is a repeatable pattern Which could allow for enums with new members added
For example here
trait Trait{
fn fun(&self);
}
enum Enum{
//if worried about size, use a pointer to type.
//for every type that impls trait the type is added to the enum as a member wrapping
Member(Member)
}
impl Trait for Enum {
fn fun(&self) {
match self {
//for every type that impls trait the type is added to the enum match here
Member(member)=>{
member.fun();
}
}
}
}
struct Member;
impl Trait for Member {
fn fun(&self) {
println!("Member")
}
}
//sure this functions but this can made be extendable as the pattern is repeatable
//why am putting this here Is because it's needs to access externally from the crate when used
//as a dependency Which it is outside the ability that proc macros can do
If you want to allow extending an enum outside of the original crate, then the result won't be any faster than trait objects. The reason why enums are faster is because they can work with a hard-coded set of options that are entirely known in advance, whereas trait object code has to be able to handle other implementations added elsewhere by code it doesn't know about.
The enum_dispatch
crate you mentioned is great for improving the boilerplate of using a trait for dispatch, and I'd be fine with integrating something like it into the language!
3 Likes
"The reason why enums are faster is because they can work with a hard-coded set of options that are entirely known in advance"
Is there no way to compile code for the enum after all enum members are known?
If am wrong I just learn more
I don't mind that this is non accessible by dynlibs
It's not necessarily true that trait objects would always be slower then enums.
An enum might've inherent methods that branch repeatedly upon the discriminant, which could eat CPU time. A trait object would've one vtable layer, after which all the code knows the type aka discriminant. I'd expect the trait object would be faster if you only handle one flavor at a time, and invoke multiple methods sparingly, but still have considerable discriminant related logic.
If you pass them around then trait obejcts would require boxes, which incurs allocation costs, while enums demand the size of the largest variant, which tempts tehm towards allocations too, An enum would almost always result in smaller code size, which improves cache locality, even if the largest variant cost wastes some memory.
Vec<Enum>
would always handle the discriminant check within each element. Vec<Type>
cannot become Vec<impl Trait>
easily, but it'd be interesting if you could cast Vec<Type>
to impl for<T: Trait> Vec<T>
which floats out a single vtable for the whole Vec
. I suppose you could've blanket impl VecTrait for Vec<T> where T: Trait { .. }
instead.