This is probably as good as we can get in the current system (I do something similar in my code today).
I also think you probably need both "super" and "mut_super", so it would be two methods to implement instead of one (still pretty good). I wonder whether it is possible to write a macro that automates writing these boilerplate methods? The key weakness is that (I think) the compiler can't inline the accesses to "super" so that you end up with a chain of virtual function calls every time it is accessed, so performance would be pretty bad. On Wed, Nov 13, 2013 at 10:27 AM, Eric Reed <[email protected]>wrote: > 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 > >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
