Methods implemented on Base trait not carry over to Derived trait object

(Issue discovered in another thread.)

Why the error below? Type implements Base and Derived. Moreover, additional methods are defined for Base and Derived. A Derived trait object is not able to use the additional methods defined for Base.

trait Base { fn base(&self) -> u32; }
trait Derived: Base {}

struct Type;
impl Base for Type { fn base(&self) -> u32 { 1 } }
impl Derived for Type {}


// Additional methods for everything implementing trait Base.
impl Base {
  fn double_base(&self) -> u32 { self.base() * 2 }
}

// Additional methods for everything implementing trait Derived.
impl Derived {
  fn triple(&self) -> u32 { self.base() * 3 }
}


fn main() {
    let b: Box<Derived> = Box::new(Type);
    println!("b.base() = {:?}", b.base());

    // error: no method named `double_base` found for type `Derived` in the
    //        current scope
    //println!("b.double_base() = {:?}", (*b).double_base());

    println!("b.triple() = {:?}", b.triple());
}

Playground

The additional methods implemented on Base (double_base()), can only depend on the methods constituting Base (base()) which are accessible in the Derived trait object's vtable. So why not allow them? Is there a fundamental reason, or is this a possible oversight/un-implemented feature?

And on a closely-related note

    let c = &*b as &Base;

in main() gives

 error: non-scalar cast: `&Derived` as `&Base`

but as far as I can see, the Derived trait object reference should be convertible to a Base one -- the latter is just a subset of the vtable coupled with the same data object.

See oop - Why doesn't Rust support trait object upcasting? - Stack Overflow .

If you're looking for an actual solution, you can use extension traits.

// Additional methods for everything implementing trait Base.
trait BaseExt: Base {
    fn double_base(&self) -> u32 { self.base() * 2 }
}
impl<T: ?Sized + Base> BaseExt for T { }

// Additional methods for everything implementing trait Derived.
trait DerivedExt: Derived {
    fn triple(&self) -> u32 { self.base() * 3 }
}
impl<T: ?Sized + Derived> DerivedExt for T { }

Ah, I got so excited figuring out the real cause in the other thread that I didn't actually google it. Shame on me. :wink: Also noteworthy is that #5665 -- this feature is intended.

Thanks! That seems like a generally better way than just implementing methods a trait.