Dynamically dispatched trait objects have some attributes which can make them a better solution than enums:
- They separate the implementation for each variant into separate blocks, rather than having a bunch of methods with match statements.
- They suggest a stronger degree of parametricity by providing an interface that each variant is required to implement. This makes it obvious when, for example, one parameter only applies to one variant, which can pressure you to think about whether the abstraction is well fit.
But because they have to be virtually dispatched and behind a pointer, they carry both a performance and an ergonomics penalty.
What if they didn’t have to? If I have a private trait implemented by a half dozen concrete types, this is logically equivalent to an enum, but easier to read. What if there were a
#[repr(closed)] attribute that would represent a trait object as an enum? I think this is a good statement of the rules:
A trait tagged
- Be local (to tag it, of course)
- Be object safe (to dynamically dispatch it).
- Be implemented only by concrete types or types in which all type variables are bound by at least one closed traits (so that all concrete implementations can be determined locally).
This would then give the trait these properties:
- All impls of this trait outside of this crate are orphan impls (this is what makes it closed).
- This trait’s trait object is
Sized, having the same representation as an enum which has a variant for each implementing type, and methods perform a switch over the discriminant rather than going through virtual dispatch.
Is this potentially viable? Its stricter and more optimized than the proposals about thin traits.