Multiple subtyping with alias this and nested classes
Yigal Chripun
yigal100 at gmail.com
Mon Oct 5 15:52:42 PDT 2009
On 05/10/2009 12:19, Max Samukha wrote:
> On Sun, 04 Oct 2009 12:31:08 -0400, Yigal Chripun<yigal100 at gmail.com>
> wrote:
>
>> Max Samukha Wrote:
>>>>
>>>> I see. What you want is non-virtual MI.
>>>> I don't think that allowing the derived class to have two distinct implementations for the same function prototype is a good idea.
>>>> Eiffel handles this by giving the programmer controls to select features and rename them in the derived class which I think is better.
>>>>
>>>> // hypothetical syntax example
>>>> class FlippingBlipper : IBlipper, IFilpper {
>>>> mixin Flipper F;
>>>> mixin Blipper B;
>>>> // rename the inherited interface functions
>>>> alias IBlipper.nameCollision boo;
>>>> alias IFilpper.nameCollision foo;
>>>> // implement the now two distinct functions
>>>> void foo() { F.nameCollision(); }
>>>> void boo() { B.nameCollision(); }
>>>> }
>>>>
>>>> you can further subtype and the derived foo& boo will override the respective interfaces.
>>>
>>> Yes, but what if nameCollision is a virtual function called somewhere
>>> in the template mixin? Your example has effectively removed the
>>> virtuality.
>>>
>>
>> it doesn't remove virtuality. Virtual functions are stored as pointers in the vtable. with my suggested solution the idea is that the same pointer in the vtable gets a new name in the derived class.
>> when you mixin the template into the derived class the compiler would resolve nameCollision to the new name "foo" because of the renaming rule in the derived class.
>
> Ok, I still cannot see how the compiler can reliably determine that
> IFlipper.nameCollision is implemented by Flipper and not by Blipper
> and call the correct override when flip is called.
>
> Should the compiler deduce that from F.nameCollision? If yes, what
> about:
> void foo() { B.nameCollision; F.nameCollision; } ?
>
> Or should it decide based on the fact that Flipper contains the 'flip'
> function that implements IFlipper.flip? If yes, then what if the
> interfaces had nothing more than the 'nameCollision' functions?
>
I see you want to discuss the details of the renaming mechanism, while I
just talked about the general idea itself until now.
we have two cases: regular and mixins.
for case a it's simple, the class itself lists the renames:
Interface A {
void foo();
}
Interface B {
void foo();
}
class C : A, B {
alias A.foo func1; // or similar syntax to mark the renaming
alias B.foo func2; // ditto
override void func1() {...} // C.func1 overrides A.foo
override void func2() {...} // C.func2 overrides B.foo
}
case 2, mixins:
I think some sort of annotations by the programmer is needed.
class C : A, B {
alias A.foo func1; // or similar syntax to mark the renaming
alias B.foo func2; // ditto
// hypothetical syntax to connect mixins to interfaces
// the compiler will apply the rename rules of this class assuming that
// any references to foo in ImplA are "A.foo" and will be renamed to
// func1 in C
// if the mixin explicitly specifies the interface (e.g B.foo) than the
// compiler already knows what to map this to.
mixin ImplA A;
mixin ImplB B;
}
btw, this all can be done in a much simpler way with (hygienic) AST Macros.
>> I don't think I want non virtual MI in D since it is more trouble than it's worth. but *if* we discuss this, I think my suggested semantics are simpler. The syntax probably can be much better but that's a secondary issue IMO.
>>
>
> It's unrelated to virtual MI. See Sergey Gromov's post. We are
> discussing this only because it's a real world problem that has no
> decent solution in D.
>
I said *non* virtual MI above..
>>
>> with my design:
>> class Foo : FlippingBlipper {
>> override foo ...
>> override bar ...
>> }
>> IFlipper obj = new Foo;
>> obj.nameCollision; // will call Foo.bar
>
>>
>> I don't think that's possible with your design.
>
> I'm not claiming it's my design. Andrei is the author.
>
> And yes, it's possible in a number of ways. One is:
>
> class BlippingFlipper
> {
> class Flipper_ : Flipper
> {
> override void nameCollision() { foo(); }
> final void super_nameCollision() { super.nameCollision; }
> }
>
> this() { flipper = new Flipper_; }
>
> Flipper_ flipper;
> alias flipper this;
>
> void foo() { flipper.super_nameCollision; }
> }
>
> class Foo : BlippingFlipper
> {
> override void foo() {}
> }
>
> (Wordy but still possible. Can be made easier on the eye with a helper
> mixin)
This gets more and more complicated - Like I said before, I feel that
renaming has easier to understand semantics.
>
> I agree that possibility to implement renamed interface methods AND
> explicit interface implementation would solve the problem of name
> collisions. But it doesn't solve the problem of subtyping structs and
> built-in types.
>
the problem with explicit interface implementation as discussed in
another thread is that the implementations will become hidden.
class C: A, B {
override void A.foo () { ... }
override void B.foo () { ... }
}
C obj = new C;
obj.foo(); // error
class D : C { ... }
what happens in class D? Can I override the functions there as well? how?
you do not need explicit interface implementation at all if you have
renaming.
>>
>> besides, alias this is a hack. a better mechanism would be to have compile-time inheritance, IMO.
>
> I think 'alias this' is a powerful feature.
>
> Given the constraints like "easy for the compiler writer to implement"
> and "we have many other things to do", I doubt traits or something
> like that will be or needs to be in the language.
Alias this is powerful black magic. being powerful doesn't make it any
less dark.
More information about the Digitalmars-d
mailing list