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

Reply via email to