Given this code:
trait Base {
fn a(&self);
fn b(&self);
fn c(&self);
fn d(&self);
}
trait Derived : Base {
fn e(&sel
As of Jun 2017, the status of this "sub-trait coercion" (or "super-trait coercion") is as follows:
coerce_inner(
T
) =U
whereT
is a sub-trait ofU
;
There is also a duplicate issue #5665. Comments there explain what prevent this from being implemented.
+-----+-------------------------------+ | 0- 7|pointer to "drop glue" function| +-----+-------------------------------+ | 8-15|size of the data | +-----+-------------------------------+ |16-23|alignment of the data | +-----+-------------------------------+ |24- |methods of Self and supertraits| +-----+-------------------------------+It doesn't contain a vtable for a super-trait as a subsequence. We have at least to have some tweaks with vtables.
There @typelist says they prepared a draft RFC which looks well-organized, but they look like disappeared after that (Nov 2016).
I ran into the same wall when I started with Rust. Now, when I think about traits, I have a different image in mind than when I think about classes.
trait X: Y {}
means when you implement trait X
for struct S
you also need to implement trait Y
for S
.
Of course this means that a &X
knows it also is a &Y
, and therefore offers the appropriate functions.
It would require some runtime-effort (more pointer dereferences) if you needed to traverse pointers to Y
's vtable first.
Then again, the current design + additional pointers to other vtables probably wouldn't hurt much, and would allow easy casting to be implemented. So maybe we need both? This is something to be discussed on internals.rust-lang.org
Actually, I think I got the reason. I found an elegant way to add upcasting support to any trait that desires it, and that way the programmer is able to choose whether to add that additional vtable entry to the trait, or prefer not to, which is a similar trade-off as in C++'s virtual vs. non-virtual methods: elegance and model correctness vs. performance.
The code can be implemented as follows:
trait Base: AsBase {
// ...
}
trait AsBase {
fn as_base(&self) -> &Base;
}
impl<T: Base> AsBase for T {
fn as_base(&self) -> &Base {
self
}
}
One may add additional methods for casting a &mut
pointer or a Box
(that adds a requirement that T
must be a 'static
type), but this is a general idea. This allows for safe and simple (although not implicit) upcasting of every derived type without boilerplate for every derived type.