Here's how I would do it using just existing Rust (assuming this hasn't all
changed under me in the past couple months).
NB: I haven't actually tried compiling this, but I'm pretty sure it (or
something like it) would work.
Nice properties over this solution:
- Doesn't require language extensions (although syntax sugar wouldn't be
unwelcome)
- Doesn't require trait objects (i.e. static dispatch is possible)
- Only need to implement one method for each derived type (super) in
addition to overridden methods
- Supports multiple inheritance in two ways (and avoids the diamond problem
I think -- not a C++ expert so I may have misunderstood that)
+ no default parent and programmer must select which parent to use
before calling
+ implementer-chosen default parent and programmer can chose to use a
different parent if desired
Neutral?:
- Doesn't enforce or care about the prefix property. Not sure if that still
matters so much w/o dynamic dispatch.
Downsides:
- Performance of delegation depends on LLVM's ability to inline (I think).
- Does require repeating all the methods once (for delegating default
implementations)
// The base type
struct Base {
data : int;
}
// Characterize it's extensible behavior in a trait
trait Trait {
fn method(&self);
}
// Implement the base behavior
impl Trait for Base {
fn method(&self) { ... }
}
// Extension of trait that supports upcasting to existing implementations
trait DerivingTrait<P : Trait> : Trait {
// one extra method for accessing a parent's implementation. ideally
this would be inlined by the compiler
fn super(&self) -> P;
// default implementations for all the methods in Trait let us avoid
writing delegation everywhere manually
fn method(&self) {
self.super().method() // just delegate to parent
}
}
// Single inheritance
struct Single {
parent: Base,
moreData: int,
}
impl DerivingTrait<Base> for Single {
fn super(&self) -> Base { self.parent }
}
// Overriding behavior
struct Override {
parent: Base,
otherData: u8,
}
impl DerivingTrait<Base> for Override {
fn super(&self) -> Base { self.parent }
fn method(&self) { ... }
}
// Multiple inheritance
struct Multiple {
single: Single,
override: Override,
evenMoreData: ~str,
}
// must specify which parent's implementation we want (could hide wrapping
inside of as_* methods impl'd on Multiple if you like)
// if we want one of them as the default, then we can impl DerivingTrait on
Multiple directly
struct MultipleAsSingle(Multiple);
struct MultipleAsOverride(Multiple);
impl DerivingTrait<Single> for MultipleAsSingle {
fn super(&self) -> Single { self.single }
}
impl DerivingTrait<Override> for MultipleAsOverride {
fn super(&self) -> Override { self.override }
}
fn main() {
let base = Base { ... };
let single = Single { ... };
let override = Override { ... };
let multiple = Multiple { ... };
base.method();
base.super(); // compile time error
single.method(); // =inline delegation=> single.super().method()
=inline upcast=> single.base.method()
override.method(); // done! no delegating
MultipleAsSingle(multiple).method(); // =delegate=>
MAS(multiple).super().method() =upcast=> multiple.single.method()
=delegate=> multiple.single.super().method() =upcast=>
multiple.single.base.method()
MutlipleAsOverride(multiple).method(); // =delegate=>
MAO(multiple).super().method() =upcast=> multiple.override.method()
}
Thoughts?
Eric
On Tue, Nov 12, 2013 at 10:30 PM, Kevin Ballard <[email protected]> wrote:
> On Nov 12, 2013, at 10:26 PM, Kevin Ballard <[email protected]> wrote:
>
> > And even that restriction could be lifted if ~Trait objects could be
> represented using an array of pointers (one to each inherited struct), e.g.
> ([*A,*B,*C],*vtable) instead of just (*A,*vtable), though I suspect this is
> not worth doing.
>
> Upon further reflection, this would need to be done anyway because of the
> ability to combine traits. If I have
>
> trait TraitA : A {}
> trait TraitB : B {}
>
> and I want to use ~TraitA+TraitB then I would need a "fat" trait. Although
> in this case the number of value pointers is equal to the number of
> combined traits, so it's a bit more sensible to allow for "fat" trait
> pointers here.
>
> -Kevin
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
>
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev