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

Reply via email to