Is there any reason for this code to be not compiled?
// Nightly
#![feature(trait_upcasting)]
#![allow(incomplete_features)]
trait A {
fn first(&self);
}
trait B {
fn second(&self);
}
trait C {
// IMAGINE HEAVY VERSION OF A OR DIFFERENT FUNCTIONAL
fn first(&self);
}
trait AB: A + B {}
impl<T: A + B> AB for T {}
trait BC: B + C {}
impl<T: B + C> BC for T {}
trait ABC: A + B + C {}
impl<T: A + B + C> ABC for T {}
// STRUCT + IMPL
struct ABCStruct {}
impl A for ABCStruct {
fn first(&self) {
println!("A FIRST")
}
}
impl B for ABCStruct {
fn second(&self) {
println!("B SECOND")
}
}
impl C for ABCStruct {
fn first(&self) {
println!("C FIRST")
}
}
// USERS
fn use_ab(ab: &dyn AB) {
ab.first()
}
fn use_bc(bc: &dyn BC) {
bc.first()
}
fn use_a(a: &dyn A) {
a.first()
}
fn ab_from_abc(abc: &dyn ABC) {
use_ab(abc as &dyn AB)
}
fn bc_from_abc(abc: &dyn ABC) {
use_bc(abc as &dyn BC)
}
fn a_from_abc(abc: &dyn ABC) {
use_a(abc as &dyn A)
}
fn main() {
let abc = ABCStruct {};
ab_from_abc(&abc as &dyn ABC);
bc_from_abc(&abc as &dyn ABC);
a_from_abc(&abc as &dyn ABC);
}
There is the working version which I don't like (because of strange bounds):
If we forget about AB + BC additional bounds, then what reasons to not implement AB trait for ABC?
Most possible that I'm wrong but for know I think that: All traits with bound ChildN (N = 1, 2, ...) must be implmented for all traits ParentN (N = 1, 2, ...), as long as the set of ChildNbasic traits is a subset of the set of ParentNbasic trait.
I suppose that trait is basic when:
It's have associated type or function (A, B, C, Error)
It's have no bounds (Marker traits Send, Sync and possible user defined)
Notice that I don't ask to removeAB, I just wan't to auto implement (where is obviously possible)
I hope that you will point me on my misunderstanding or \ and appreciate by idea
If you have other solution for this in current Rust I will really glad to see
I feel like this thread could get better and quicker responses (and could be a better fit in general) on users.rust-lang.org
Especially any good answer I could give would mostly (or rather exclusively) consist of explanations on how Rust works, and not consists of any discussions on how Rust design could/should be changed, but I don’t feel like doing too in-depth explanations/explorations of “how does Rust work” on the internals forum.
For now… in short: If you want a trait object dyn AB, there needs to be a vtable for it, and there’s nothing in trait ABC: A + B + C that could suggest to the compiler that a (pointer to a) dyn AB vtable should be included in a dyn ABC vtable, hence upcasting &dyn ABC to &dyn AB is not possible. You also cannot simply generate all possible vtables for all possible combinations of supertraits on mere speculation that there could be a need for it (that would quickly blow up to too many possible combinations).