Getting `dyn AB` from `dyn ABC` trait if both bounds `A + B`

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 ChildN basic traits is a subset of the set of ParentN basic 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 remove AB, 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 :slight_smile:

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).

4 Likes

I think this subject is suitable to irlo if it's proposing a new language feature. But this is already in nightly (in an incomplete state)

https://doc.rust-lang.org/beta/unstable-book/language-features/trait-upcasting.html

1 Like

It seems like it's not incomplete already. Check last checkbox