Summary
- Include pre-monomorphised compiled version for items that are generic over object-safe trait objects when building a library crate;
- Introduce a way for compiler to introduce dynamic dispatch “under the hood”, without modifying source code from
<T> to &dyn.
- Introduce a hint like
#[prefer_dyn] that tells this generic item should be preferrably used in a dynamic way, even if source code looks generic. There can also be a more aggressive opt_level=s optimization making compiler introducing dyndispatch even not when asked.
Motivation
I saw a comment that compains that there is too much generic and too little dynamic in the ecosystem, leading unavoidably increased compile times and maybe binary sizes.
But explicitly making library APIs based dynamic dispatch instead of generic seems like a stepping down from Rust ideas and revoking user’s capability to use it in a generic way.
Example
Library:
pub trait MyTrait { fn lol(&self); }
struct Q1; struct Q2; struct Q3;
impl MyTrait for Q1, Q2, Q3 {...};
#[please_prefer_dyn_here]
fn my_func<T:MyTrait>(x : T) {
// do something heavyweight, that requires a lof of compilation efforts
// and not worth inlining or duplicating across those used types,
// yet not revoking users of the generic use entirely.
}
- Generic version serialized and included in rlib, like usual;
- Additionally, a version as if it were
fn my_func(x : &MyTrait) compiled and also included in rlib.
- Library author can think again and just remove the attribute to easily revert to generic use without the artificial dyndispatch.
- Attribute can be added in backward compatible way.
User:
my_func(Q1);
my_func(Q2);
#[please_prefer_generic_here]
my_func(Q3);
- Looks like generic, but compiler uses dynamic dispatch under the hood, except for
Q3 because of user explicitly requested it.
- Compilation time of the user crate dropped because of no need to monomorphise, then compile
generic 2 more times.
Drawbacks
- More compile time when the feature is not used
- More compilcations to the language, like usual
Alternatives
Providing helper functions like
fn foo_generic_version<T:Trait>(x: T);
fn foo(x: &Trait) {
foo_generic_version(x)
}
so that dynamic dispatch becomes more popular without sacrificing static approach. Making some API Guidelines entry about that may also help.
TODO
Unresolved quesitons
TODO