The call isn't statically dispatched when I invoke a method via a trait
pointer. So it seems when I invoke any trait function, I pay double the
cost of a virtual function call instead of one... I suppose it isn't _too_
bad, but it still hurts.



On Wed, Nov 13, 2013 at 12:21 PM, Eric Reed <ecr...@cs.washington.edu>wrote:

> 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