I'm not clear on why LLVM wouldn't be able to inline super() calls. It's static dispatch, so it knows exactly what function is being called.
On Wed, Nov 13, 2013 at 1:25 AM, Oren Ben-Kiki <o...@ben-kiki.org> wrote: > 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 <ecr...@cs.washington.edu>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 <ke...@sb.org> wrote: >> >>> On Nov 12, 2013, at 10:26 PM, Kevin Ballard <ke...@sb.org> 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 >>> Rust-dev@mozilla.org >>> https://mail.mozilla.org/listinfo/rust-dev >>> >>> >> >> _______________________________________________ >> Rust-dev mailing list >> Rust-dev@mozilla.org >> https://mail.mozilla.org/listinfo/rust-dev >> >> >
_______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev