www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Multiple subtyping with alias this and nested classes

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
I just realized that nested classes work so well with alias this, you'd 
think it was an evil plot all along. It wasn't, but I'm happy about the 
coincidence.

Here's how to effect multiple subtyping in D very effectively:

import std.stdio;

class Base1 {
     void fun() { writeln("Base.fun"); }
}

class Base2 {
     void gun() { writeln("Base.fun"); }
}

class Multiple : Base1 {
     // Override method in Base1
     override void fun() { writeln("Multiple.fun"); }
     // Override method in Base2
     class MyBase2 : Base2 {
         override void gun() { writeln("Multiple.gun"); }
     }
     // Effect multiple subtyping
     Base2 _base2;
     alias _base2 this;
     this() {
         _base2 = new MyBase2;
     }
}

void main()
{
     auto obj = new Multiple;
     Base1 obj1 = obj;
     obj1.fun();
     Base2 obj2 = obj;
     obj2.gun();
}

The program above segfaults because somehow obj2 is null. That is a bug 
I just reported. For now, you can replace obj2.gun() with obj.gun() to 
make things work.

When we first introduced alias this, I knew multiple subtyping was 
possible. I didn't expect it to dovetail so nicely with nested classes.


Andrei
Oct 02 2009
next sibling parent reply language_fan <foo bar.com.invalid> writes:
Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu thusly wrote:

 I just realized that nested classes work so well with alias this, you'd
 think it was an evil plot all along. It wasn't, but I'm happy about the
 coincidence.
 
 Here's how to effect multiple subtyping in D very effectively:
 
 import std.stdio;
 
 class Base1 {
      void fun() { writeln("Base.fun"); }
 }
 
 class Base2 {
      void gun() { writeln("Base.fun"); }
 }
 
 class Multiple : Base1 {
      override void fun() { writeln("Multiple.fun"); } 
      class MyBase2 : Base2 {
          override void gun() { writeln("Multiple.gun"); }
      }
      // Effect multiple subtyping
      Base2 _base2;
      alias _base2 this;
      this() {
          _base2 = new MyBase2;
      }
 }

I do not get why didn't you just use the 'import' keyword here instead of alias, since what you are basically doing is importing the symbols from one scope to another. It would seem a perfect generalization of import to also include cases where 'with' is currently used and also alias. The use of the term 'alias' is somewhat confusing.
Oct 02 2009
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
language_fan wrote:
 Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu thusly wrote:
 
 I just realized that nested classes work so well with alias this, you'd
 think it was an evil plot all along. It wasn't, but I'm happy about the
 coincidence.

 Here's how to effect multiple subtyping in D very effectively:

 import std.stdio;

 class Base1 {
      void fun() { writeln("Base.fun"); }
 }

 class Base2 {
      void gun() { writeln("Base.fun"); }
 }

 class Multiple : Base1 {
      override void fun() { writeln("Multiple.fun"); } 
      class MyBase2 : Base2 {
          override void gun() { writeln("Multiple.gun"); }
      }
      // Effect multiple subtyping
      Base2 _base2;
      alias _base2 this;
      this() {
          _base2 = new MyBase2;
      }
 }

I do not get why didn't you just use the 'import' keyword here instead of alias, since what you are basically doing is importing the symbols from one scope to another. It would seem a perfect generalization of import to also include cases where 'with' is currently used and also alias. The use of the term 'alias' is somewhat confusing.

Well if we did use 'import' people would have asked why we don't use 'alias' because that's much closer to what really happens. Note that the feature does not only import symbols from one scope to another. It just allows you to substitute some expression when someone tries to use this under another type. Andrei
Oct 02 2009
prev sibling next sibling parent reply Max Samukha <spambox d-coding.com> writes:
On Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:

I just realized that nested classes work so well with alias this, you'd 
think it was an evil plot all along. It wasn't, but I'm happy about the 
coincidence.

Here's how to effect multiple subtyping in D very effectively:

import std.stdio;

class Base1 {
     void fun() { writeln("Base.fun"); }
}

class Base2 {
     void gun() { writeln("Base.fun"); }
}

class Multiple : Base1 {
     // Override method in Base1
     override void fun() { writeln("Multiple.fun"); }
     // Override method in Base2
     class MyBase2 : Base2 {
         override void gun() { writeln("Multiple.gun"); }
     }
     // Effect multiple subtyping
     Base2 _base2;
     alias _base2 this;
     this() {
         _base2 = new MyBase2;
     }
}

void main()
{
     auto obj = new Multiple;
     Base1 obj1 = obj;
     obj1.fun();
     Base2 obj2 = obj;
     obj2.gun();
}

The program above segfaults because somehow obj2 is null. That is a bug 
I just reported. For now, you can replace obj2.gun() with obj.gun() to 
make things work.

When we first introduced alias this, I knew multiple subtyping was 
possible. I didn't expect it to dovetail so nicely with nested classes.


Andrei

Neat! But what if there is Base3? Is it supposed to be subtyped like this: class Base3 { void run() {} } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln("Multiple.fun"); } // Override method in Base2 class MyBase2 : Base2 { class MyBase3 : Base3 { override void run() { writeln("Multiple.run"); } } MyBase3 _base3; this() { _base3 = new MyBase3; } alias _base3 this; override void gun() { writeln("Multiple.gun"); } } // Effect multiple subtyping MyBase2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } ? Note that there is an additional level of indirection per each subtype: auto m = new Multiple; m.run is unrolled to m._base2._base3.run
Oct 02 2009
next sibling parent Max Samukha <spambox d-coding.com> writes:
On Fri, 02 Oct 2009 21:41:54 +0300, Max Samukha <spambox d-coding.com>
wrote:

Note that there is an additional level of indirection per each
subtype:

Oct 02 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Max Samukha wrote:
 On Fri, 02 Oct 2009 13:00:05 -0500, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 
 I just realized that nested classes work so well with alias this, you'd 
 think it was an evil plot all along. It wasn't, but I'm happy about the 
 coincidence.

 Here's how to effect multiple subtyping in D very effectively:

 import std.stdio;

 class Base1 {
     void fun() { writeln("Base.fun"); }
 }

 class Base2 {
     void gun() { writeln("Base.fun"); }
 }

 class Multiple : Base1 {
     // Override method in Base1
     override void fun() { writeln("Multiple.fun"); }
     // Override method in Base2
     class MyBase2 : Base2 {
         override void gun() { writeln("Multiple.gun"); }
     }
     // Effect multiple subtyping
     Base2 _base2;
     alias _base2 this;
     this() {
         _base2 = new MyBase2;
     }
 }

 void main()
 {
     auto obj = new Multiple;
     Base1 obj1 = obj;
     obj1.fun();
     Base2 obj2 = obj;
     obj2.gun();
 }

 The program above segfaults because somehow obj2 is null. That is a bug 
 I just reported. For now, you can replace obj2.gun() with obj.gun() to 
 make things work.

 When we first introduced alias this, I knew multiple subtyping was 
 possible. I didn't expect it to dovetail so nicely with nested classes.


 Andrei

Neat! But what if there is Base3? Is it supposed to be subtyped like this: class Base3 { void run() {} } class Multiple : Base1 { // Override method in Base1 override void fun() { writeln("Multiple.fun"); } // Override method in Base2 class MyBase2 : Base2 { class MyBase3 : Base3 { override void run() { writeln("Multiple.run"); } } MyBase3 _base3; this() { _base3 = new MyBase3; } alias _base3 this; override void gun() { writeln("Multiple.gun"); } } // Effect multiple subtyping MyBase2 _base2; alias _base2 this; this() { _base2 = new MyBase2; } } ? Note that there is an additional level of indirection per each subtype: auto m = new Multiple; m.run is unrolled to m._base2._base3.run

Multiple alias this declarations must be allowed. Andrei
Oct 02 2009
prev sibling next sibling parent reply Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  2 de octubre a las 13:00 me escribiste:
 I just realized that nested classes work so well with alias this,
 you'd think it was an evil plot all along. It wasn't, but I'm happy
 about the coincidence.
 
 Here's how to effect multiple subtyping in D very effectively:
 
 import std.stdio;
 
 class Base1 {
     void fun() { writeln("Base.fun"); }
 }
 
 class Base2 {
     void gun() { writeln("Base.fun"); }
 }
 
 class Multiple : Base1 {
     // Override method in Base1
     override void fun() { writeln("Multiple.fun"); }
     // Override method in Base2
     class MyBase2 : Base2 {
         override void gun() { writeln("Multiple.gun"); }
     }
     // Effect multiple subtyping
     Base2 _base2;
     alias _base2 this;
     this() {
         _base2 = new MyBase2;
     }
 }
 
 void main()
 {
     auto obj = new Multiple;
     Base1 obj1 = obj;
     obj1.fun();
     Base2 obj2 = obj;
     obj2.gun();
 }
 
 The program above segfaults because somehow obj2 is null. That is a
 bug I just reported. For now, you can replace obj2.gun() with
 obj.gun() to make things work.
 
 When we first introduced alias this, I knew multiple subtyping was
 possible. I didn't expect it to dovetail so nicely with nested
 classes.

We might have very different taste, but I find that a little... horrible. What do you have against mixins? I think you're trying to use D as C++ :) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- EL PRIMER MONITO DEL MILENIO... -- Crónica TV
Oct 02 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Leandro Lucarella wrote:
 We might have very different taste, but I find that a little... horrible.
 What do you have against mixins? I think you're trying to use D as C++ :)

If mixins work better, all the better. How would you use them to achieve multiple inheritance? Andrei
Oct 02 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Leandro Lucarella wrote:
 Andrei Alexandrescu, el  2 de octubre a las 19:10 me escribiste:
 Leandro Lucarella wrote:
 We might have very different taste, but I find that a little... horrible.
 What do you have against mixins? I think you're trying to use D as C++ :)

achieve multiple inheritance?

Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead.

But you're just saying it. I think you'd agree I wouldn't just follow that dogma noncritically just because you told me what to do. I don't think many people design with multiple inheritance in mind. They design aiming at a good design. In my experience, some designs can make gainful use of multiple inheritance of classes, and some of my best designs do use multiple inheritance simply because it was the best tool for the job. Scala supports that with mixins, D supports that with multiple subtyping. Andrei
Oct 03 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Leandro Lucarella wrote:
 Andrei Alexandrescu, el  3 de octubre a las 11:23 me escribiste:
 Leandro Lucarella wrote:
 Andrei Alexandrescu, el  2 de octubre a las 19:10 me escribiste:
 Leandro Lucarella wrote:
 We might have very different taste, but I find that a little... horrible.
 What do you have against mixins? I think you're trying to use D as C++ :)

achieve multiple inheritance?

for common functionality instead.

follow that dogma noncritically just because you told me what to do.

No, because the language is designed to do that AFAIK, so it will be much easier and clear (for who writes the code and who reads it). I think you hack with alias this is more obscure (we might be hitting personal taste here, I grant you that).

Alias this was introduced purposedly to allow multiple subtyping. Until yesterday, however, I hadn't realized how much nested classes help with that. Even before that I wasn't worried, since MI designs are not as frequent as SI designs.
 I don't think many people design with multiple inheritance in mind.
 They design aiming at a good design.

But you always have to take into account the tools you have when designing. What's the point of designing a perfect bridge assuming you have a material that doesn't exist? Of course you can do that, but when you hit reality, you'll have to "hack" your design to fit your real tools. So you can design something that "looks like" multiple-inheritance, because it's easier (or nicer) to do so. But when you want to put that in reality, you have to choose what tool to use. In C++ you probably want to use MI (because the language has a good support for it), but in D you probably want to use interfaces + mixins (because the language has good support for it). Of course you can even implement it in C, or even assembly; you can implement it as in C in C++ or D too, but it would be harder and more obscure.
 In my experience, some designs can make gainful use of multiple
 inheritance of classes, and some of my best designs do use multiple
 inheritance simply because it was the best tool for the job.

Sure, the problem comes when the language don't support MI ;) So, there we are, you have D, which doesn't support MI per se, you have to hack it. You can do it with the nested-inherited-classes+alias-this hack, or by using interfaces+mixins. We agree at least that you have the same result with both right? Then, I guess is just a matter of taste. I simply find much more obscure and complex the nested-inherited-classes+alias-this hack than interfaces+mixins :)

I don't see using a nested class (or any class) with alias this as a hack. It's the way the whole thing is supposed to work in the first place.
 Scala supports that with mixins, D supports that with multiple
 subtyping.

I don't know what you mean about multiple subtyping.

You subtype once by using inheritance, and then some more by using alias this. Andrei
Oct 03 2009
parent reply Max Samukha <spambox d-coding.com> writes:
On Sat, 3 Oct 2009 14:11:37 -0300, Leandro Lucarella
<llucax gmail.com> wrote:

Ok, then, I just find it ugly and unnecessary since you can do the same
with interfaces+mixins.

Actually, you can't. Consider: interface IBlipper { void blip(); void nameCollision(); } template Blipper() { void blip() {} void nameCollision() {} } interface IFlipper { void flip(); void nameCollision(); } template Flipper() { void flip() {} void nameCollision() {} } class FlippingBlipper : IBlipper, IFilpper { mixin Flipper; mixin Blipper; } The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. We would probably be able to overcome the limitation if and when explicit interface instantiation is implemented: template Blipper() { void IBlipper.blip() {} void IBlipper.nameCollision() {} } template Flipper() { void IFlipper.flip() {} void IFlipper.nameCollision() {} } Until then, mixin + interface just doesn't work.
It's just a matter of personal preferences (as
I said in my first mail), there is no point on arguing about it. =)

Oct 03 2009
next sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
On 03/10/2009 20:19, Max Samukha wrote:
 On Sat, 3 Oct 2009 14:11:37 -0300, Leandro Lucarella
 <llucax gmail.com>  wrote:

 Ok, then, I just find it ugly and unnecessary since you can do the same
 with interfaces+mixins.

Actually, you can't. Consider: interface IBlipper { void blip(); void nameCollision(); } template Blipper() { void blip() {} void nameCollision() {} } interface IFlipper { void flip(); void nameCollision(); } template Flipper() { void flip() {} void nameCollision() {} } class FlippingBlipper : IBlipper, IFilpper { mixin Flipper; mixin Blipper; } The above sucks because we can't specify which nameCollision gets implemented by which mixin. In current D, nameCollision of both interfaces is implemented by Flipper. We would probably be able to overcome the limitation if and when explicit interface instantiation is implemented: template Blipper() { void IBlipper.blip() {} void IBlipper.nameCollision() {} } template Flipper() { void IFlipper.flip() {} void IFlipper.nameCollision() {} } Until then, mixin + interface just doesn't work.
 It's just a matter of personal preferences (as
 I said in my first mail), there is no point on arguing about it. =)


interfaces implement virtual MI, so FlippingBlipper must implement one nameCollision which is shared by both interfaces. however you can give names to mixins so that you could choose which implementation to use for that and also have both implementations. class FlippingBlipper : IBlipper, IFilpper { mixin Flipper F; mixin Blipper B; alias F.nameCollision nameCollision; } I wonder if the following would work: class FlippingBlipper : IBlipper, IFilpper { mixin Flipper IFilpper; mixin Blipper IBlipper; }
Oct 03 2009
next sibling parent reply Max Samukha <spambox d-coding.com> writes:
On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun <yigal100 gmail.com>
wrote:

class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper F;
     mixin Blipper B;
     alias F.nameCollision nameCollision;
}

The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable.
I wonder if the following would work:

class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper IFilpper;
     mixin Blipper IBlipper;
}

I don't think so.
Oct 04 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
Max Samukha Wrote:

 On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun <yigal100 gmail.com>
 wrote:
 
class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper F;
     mixin Blipper B;
     alias F.nameCollision nameCollision;
}

The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable.
I wonder if the following would work:

class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper IFilpper;
     mixin Blipper IBlipper;
}

I don't think so.

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.
Oct 04 2009
parent reply Max Samukha <spambox d-coding.com> writes:
On Sun, 04 Oct 2009 06:31:25 -0400, Yigal Chripun <yigal100 gmail.com>
wrote:

Max Samukha Wrote:

 On Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun <yigal100 gmail.com>
 wrote:
 
class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper F;
     mixin Blipper B;
     alias F.nameCollision nameCollision;
}

The problem is that IBlipper.nameCollision is totally unrelated to IFlipper.nameCollision (for example, if the interfaces/mixins come from third-party libraries, whose developers don't know or care about each other, e.g. Tango/Phobos :P). That's why either nameCollision must have its own implementation. In current D: auto fb = new FlippingBlipper; IFlipper f = fb; IBlipper b = fb; f.nameCollision; b.nameCollision; Both calls are dispatched to the same implementation (the one provided by Flipper template), which is incorrect and undesirable.
I wonder if the following would work:

class FlippingBlipper : IBlipper, IFilpper
{
     mixin Flipper IFilpper;
     mixin Blipper IBlipper;
}

I don't think so.

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. If your mixin template contains unimplemented or partially implemented virtual functions (for example, in case of an abstract base type), you have to derive another class to (re)implement them. Ok, I'm not arguing that mixins+interfaces cannot be used to emulate multiple subtyping. I'm arguing it has problems that may force one to resort to horrible hacks. How is it better than the solution provided by 'alias this' and nested classes? 'alias this' doesn't require mixin templates, handles name conflicts nicely, allows subtyping of value types, allows (re)implementing base functions directly in the subtype (using nested classes). BTW, your example rewriten with 'alias this' looks cleaner, IMHO: class Flipper { ... } class Blipper { ... } class FlippingBlipper { Flipper flipper; Blipper blipper; this { blipper = new Blipper; flipper = new Flipper; } alias this flipper; alias this blipper; void foo() { blipper.nameCollision; } void bar() { flipper.nameCollision; } } No interfaces, no templates, no renaming. Problem solved. Almost. We have to be able to instantiate classes in-place to avoid unnecessary allocations.
Oct 04 2009
next sibling parent Max Samukha <spambox d-coding.com> writes:
On Sun, 04 Oct 2009 15:26:53 +0300, Max Samukha <spambox d-coding.com>
wrote:

BTW, your example rewriten with 'alias this' looks cleaner, IMHO:

class Flipper { ... }
class Blipper { ... }

class FlippingBlipper {
     Flipper flipper;
     Blipper blipper;
     
     this { blipper = new Blipper; flipper = new Flipper; }

     alias this flipper;
     alias this blipper;

     void foo() { blipper.nameCollision; } 
     void bar() { flipper.nameCollision; }
}

Even cleaner: class FlippingBlipper : Flipper { Blipper blipper; this { blipper = new Blipper; } alias this blipper; void foo() { blipper.nameCollision; } void bar() { nameCollision; } // will it call Flipper.nameCollision? }
Oct 04 2009
prev sibling parent reply Yigal Chripun <yigal100 gmail.com> writes:
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.
 If your mixin template contains unimplemented or partially implemented
 virtual functions (for example, in case of an abstract base type), you
 have to derive another class to (re)implement them.
 
 Ok, I'm not arguing that mixins+interfaces cannot be used to emulate
 multiple subtyping. I'm arguing it has problems that may force one to
 resort to horrible hacks.
 
 How is it better than the solution provided by 'alias this' and nested
 classes? 'alias this' doesn't require mixin templates, handles name
 conflicts nicely, allows subtyping of value types, allows
 (re)implementing base functions directly in the subtype (using nested
 classes). 
 

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.
 BTW, your example rewriten with 'alias this' looks cleaner, IMHO:
 
 class Flipper { ... }
 class Blipper { ... }
 
 class FlippingBlipper {
      Flipper flipper;
      Blipper blipper;
      
      this { blipper = new Blipper; flipper = new Flipper; }
 
      alias this flipper;
      alias this blipper;
 
      void foo() { blipper.nameCollision; } 
      void bar() { flipper.nameCollision; }
 }
 
 No interfaces, no templates, no renaming. Problem solved. Almost. We
 have to be able to instantiate classes in-place to avoid unnecessary
 allocations.

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. besides, alias this is a hack. a better mechanism would be to have compile-time inheritance, IMO.
Oct 04 2009
parent reply Max Samukha <spambox d-coding.com> writes:
On Sun, 04 Oct 2009 12:31:08 -0400, Yigal Chripun <yigal100 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 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.
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) 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.
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.
Oct 05 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
On 05/10/2009 12:19, Max Samukha wrote:
 On Sun, 04 Oct 2009 12:31:08 -0400, Yigal Chripun<yigal100 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?

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.
Oct 05 2009
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Yigal Chripun wrote:
 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.

So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei
Oct 05 2009
parent reply Yigal Chripun <yigal100 gmail.com> writes:
On 06/10/2009 02:15, Andrei Alexandrescu wrote:
 Yigal Chripun wrote:
 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.

So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei

D already has syntax for sub-typing reference types and alias this introduces a completely different syntax doing the same for value types which is bad human interface IMO. it also mixes two concepts - sub-typing and opImplicitCast (as i recall, this is done by alias this to a function) we discussed this in the past already and IIRC you agreed with me about implementing compile time inheritance for structs which I feel is much cleaner and more consistent with the existing syntax of interfaces.
Oct 05 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Yigal Chripun wrote:
 On 06/10/2009 02:15, Andrei Alexandrescu wrote:
 Yigal Chripun wrote:
 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.

So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei

D already has syntax for sub-typing reference types and alias this introduces a completely different syntax doing the same for value types which is bad human interface IMO.

Inheritance is a bit more than just subtyping, for example it entails the prefix property (otherwise it wouldn't be very practical). That's why D only allows single inheritance of state; multiple inheritance of state causes more problems than it solves. That's also why alias this is a very flexible complement to inheritance - it offers subtyping without requiring the prefix property and leaves layout to the discretion of the user.
 it also mixes two concepts - sub-typing and opImplicitCast (as i recall, 
 this is done by alias this to a function)

opImplicitCast hasn't been implemented and probably alias this will render it unnecessary. I don't see a dangerous conflation.
 we discussed this in the past already and IIRC you agreed with me about 
 implementing compile time inheritance for structs which I feel is much 
 cleaner and more consistent with the existing syntax of interfaces.

Maybe there's a misunderstanding. Inheritance of interfaces for structs (which is different from what alias this helps with) was something that Walter and I considered interesting to pursue for simplifying concept checking. However, recent developments clarified that that's not enough (I even deleted the related enhancement requests from bugzilla). Currently I'm considering a reflection-based concept checking, but it's too crude an idea to discuss it at the moment. Andrei
Oct 06 2009
parent Yigal Chripun <yigal100 gmail.com> writes:
On 06/10/2009 09:03, Andrei Alexandrescu wrote:
 Yigal Chripun wrote:
 On 06/10/2009 02:15, Andrei Alexandrescu wrote:
 Yigal Chripun wrote:
 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.

So how does this work? Alias this was meant very clearly for allowing subtyping. Conversely, using it for subtyping is precisely how it was meant to be used. How exactly did you decide it was a hack or black magic or whatever? Andrei

D already has syntax for sub-typing reference types and alias this introduces a completely different syntax doing the same for value types which is bad human interface IMO.

Inheritance is a bit more than just subtyping, for example it entails the prefix property (otherwise it wouldn't be very practical). That's why D only allows single inheritance of state; multiple inheritance of state causes more problems than it solves. That's also why alias this is a very flexible complement to inheritance - it offers subtyping without requiring the prefix property and leaves layout to the discretion of the user.

inheritance is a broken concept as it mixes sub-typing (when you implement an interface or protocol) and sub-classing which means inheritance of the implementation (state, function bodies). I said sub-typing and i meant only that: interface A; interface B; struct S: A, B; S is a sub-type of A and it must provide all the methods as defined by A. reference types (classes) provide in addition run-time polymorphism since you can have a reference of a base type point to a sub-type object. consider: struct A { int a; void foo(); } struct B { int a; int b; void foo(); } void bar(A a) { a.foo; } it should be possible to say that B is sub-type of A and pass it to bar.
 it also mixes two concepts - sub-typing and opImplicitCast (as i
 recall, this is done by alias this to a function)

opImplicitCast hasn't been implemented and probably alias this will render it unnecessary. I don't see a dangerous conflation.

 we discussed this in the past already and IIRC you agreed with me
 about implementing compile time inheritance for structs which I feel
 is much cleaner and more consistent with the existing syntax of
 interfaces.

Maybe there's a misunderstanding. Inheritance of interfaces for structs (which is different from what alias this helps with) was something that Walter and I considered interesting to pursue for simplifying concept checking. However, recent developments clarified that that's not enough (I even deleted the related enhancement requests from bugzilla). Currently I'm considering a reflection-based concept checking, but it's too crude an idea to discuss it at the moment. Andrei

can you elaborate on why is this not enough? what else is missing? My understanding is that alias this provides two things: implicit convert sub-typing IMO, explicit convert is better than the former and the latter should be provided by interfaces. struct A; struct B { alias this A; ... } this is the same as saying: interface I; struct A : I; struct B: I;
Oct 06 2009
prev sibling parent Max Samukha <spambox d-coding.com> writes:
On Tue, 06 Oct 2009 00:52:42 +0200, Yigal Chripun <yigal100 gmail.com>
wrote:


just talked about the general idea itself until now.

Yes, I understand the idea and am trying to imagine it in the context of D.
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
}

Ok, that looks good.
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;
}

This exact syntax won't work but I see your point.
btw, this all can be done in a much simpler way with (hygienic) AST Macros.

Sadly (or for the better), we are not going to have macros in the near future.
 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..

But virtual inheritance is C++'s way to resolve the diamond problem. I don't think it is related to our discussion in any way.
This gets more and more complicated - Like I said before, I feel that 
renaming has easier to understand semantics.

As an exercise, I'm working on a mixin that will allow to subtype a class and rename/override its virtual functions like this: class FlippingBlipper { mixin Subclass!(Flipper, "nameCollision", "foo") flipper; this() { flipper.construct(...); } void foo() { ... } } Save for some bugs in the compiler, it should work reasonably well. Or maybe not.
 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.

Could you explain why it is dark?
Oct 06 2009
prev sibling parent Sergey Gromov <snake.scaly gmail.com> writes:
Sun, 04 Oct 2009 00:10:30 +0200, Yigal Chripun wrote:

 interface IBlipper
 {
     void blip();
     void nameCollision();
 }
 template Blipper()
 {
     void blip() {}
     void nameCollision() {}
 }

 interface IFlipper
 {
     void flip();
      void nameCollision();
 }
 template Flipper()
 {
     void flip() {}
     void nameCollision() {}
 }

interfaces implement virtual MI, so FlippingBlipper must implement one nameCollision which is shared by both interfaces.

That's not correct if you're talking about virtual MI in C++. There, you'd have to create a common root for the virtual inheritance to actually work: class INameCollider { public: virtual void nameCollision() = 0; }; class IFlipper: public virtual INameCollider { public: virtual void flip() = 0; }; class IBlipper: public virtual INameCollider { public: virtual void blip() = 0; }; class FlippingBlipper: public IFlipper, public IBlipper { public: // Contains single, common nameCollision() virtual void nameCollision() {} virtual void flip() {} virtual void blip() {} }; Otherwise, if IFlipper and IBlipper are unrelated, you have two separate nameCollision() functions which you must disambiguate as IFlipper::nameCollision() and IBlipper::nameCollision() both when defining and when calling via a FlippingBlipper instance.
Oct 04 2009
prev sibling next sibling parent reply Rainer Deyke <rainerd eldwood.com> writes:
Max Samukha wrote:
 The above sucks because we can't specify which nameCollision gets
 implemented by which mixin. In current D, nameCollision of both
 interfaces is implemented by Flipper.

I don't think that being able to define multiple separate functions with the same name and the same signature is a necessary feature of multiple inheritance, or even a particularly well thought-out one. Python is an example of a language without this "feature", and multiple inheritance is very common in Python. -- Rainer Deyke - rainerd eldwood.com
Oct 03 2009
parent Max Samukha <spambox d-coding.com> writes:
On Sat, 03 Oct 2009 16:30:11 -0600, Rainer Deyke <rainerd eldwood.com>
wrote:

Max Samukha wrote:
 The above sucks because we can't specify which nameCollision gets
 implemented by which mixin. In current D, nameCollision of both
 interfaces is implemented by Flipper.

I don't think that being able to define multiple separate functions with the same name and the same signature is a necessary feature of multiple inheritance, or even a particularly well thought-out one.

It is not always a question of choice. For example, when you are not the designer of base types you want to subtype.
Python is an example of a language without this "feature", and multiple
inheritance
is very common in Python.

One of the reasons Python's MI is not recommended is its reliance on naming conventions. There is a note in some Python (version unknown) docs: "It is clear that indiscriminate use of multiple inheritance is a maintenance nightmare, given the reliance in Python on conventions to avoid accidental name conflicts." (http://www.python.org/doc/1.5.1p1/tut/multiple.html)
Oct 04 2009
prev sibling parent Max Samukha <spambox d-coding.com> writes:
On Sat, 03 Oct 2009 21:19:05 +0300, Max Samukha <spambox d-coding.com>
wrote:

We would probably be able to overcome the limitation if and when
explicit interface instantiation is implemented:

should be "explicit interface implementation is supported". Sorry.
Oct 04 2009
prev sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
language_fan wrote:
 On Sat, 03 Oct 2009 13:52:51 -0300, Leandro Lucarella wrote:
 
 Scala supports that with mixins, D supports that with multiple
 subtyping.


I have also not seen the specs for this feature. How does multiple subtyping work exactly in D?

The feature is very much in the works. I gave a basic example for two types. Unfortunately at the moment only one alias this declaration is allowed. The plan is to allow any number.
 Does it have exactly the same semantics as 
 using interfaces + mixing in the traits?

No.
 Why was the 'alias foo this' 
 chosen if you are also planning to add support for Scala like traits 
 (some other thread here recently discussed this).

Currently there are no plans to add support for Scala-like traits.
 Andrei, you probably 
 know how Scala chooses the overrides and overloads when traits have 
 conflicts. How does D handle this?

Walter and I are working the kinks of name lookup. If you have ideas, please share. Andrei
Oct 03 2009
prev sibling parent downs <default_357-line yahoo.de> writes:
language_fan wrote:
 Fri, 02 Oct 2009 19:35:55 -0300, Leandro Lucarella thusly wrote:
 
 We might have very different taste, but I find that a little...
 horrible. What do you have against mixins? I think you're trying to use
 D as C++ :)

So basically the diamond problem is again implementable in D, yay?

Nah, there's no ambiguity - when in doubt, the "primary" inherited class is the source of the function. AFAIK, alias this only kicks in on otherwise undefined functions.
Oct 02 2009
prev sibling next sibling parent language_fan <foo bar.com.invalid> writes:
Fri, 02 Oct 2009 19:35:55 -0300, Leandro Lucarella thusly wrote:

 We might have very different taste, but I find that a little...
 horrible. What do you have against mixins? I think you're trying to use
 D as C++ :)

So basically the diamond problem is again implementable in D, yay?
Oct 02 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  2 de octubre a las 19:10 me escribiste:
 Leandro Lucarella wrote:
We might have very different taste, but I find that a little... horrible.
What do you have against mixins? I think you're trying to use D as C++ :)

If mixins work better, all the better. How would you use them to achieve multiple inheritance?

Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- Bermú con papafritas y good show!
Oct 03 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  3 de octubre a las 11:23 me escribiste:
 Leandro Lucarella wrote:
Andrei Alexandrescu, el  2 de octubre a las 19:10 me escribiste:
Leandro Lucarella wrote:
We might have very different taste, but I find that a little... horrible.
What do you have against mixins? I think you're trying to use D as C++ :)

achieve multiple inheritance?

Don't design with multiple inheritance in mind, use interfaces + mixins for common functionality instead.

But you're just saying it. I think you'd agree I wouldn't just follow that dogma noncritically just because you told me what to do.

No, because the language is designed to do that AFAIK, so it will be much easier and clear (for who writes the code and who reads it). I think you hack with alias this is more obscure (we might be hitting personal taste here, I grant you that).
 I don't think many people design with multiple inheritance in mind.
 They design aiming at a good design.

But you always have to take into account the tools you have when designing. What's the point of designing a perfect bridge assuming you have a material that doesn't exist? Of course you can do that, but when you hit reality, you'll have to "hack" your design to fit your real tools. So you can design something that "looks like" multiple-inheritance, because it's easier (or nicer) to do so. But when you want to put that in reality, you have to choose what tool to use. In C++ you probably want to use MI (because the language has a good support for it), but in D you probably want to use interfaces + mixins (because the language has good support for it). Of course you can even implement it in C, or even assembly; you can implement it as in C in C++ or D too, but it would be harder and more obscure.
 In my experience, some designs can make gainful use of multiple
 inheritance of classes, and some of my best designs do use multiple
 inheritance simply because it was the best tool for the job.

Sure, the problem comes when the language don't support MI ;) So, there we are, you have D, which doesn't support MI per se, you have to hack it. You can do it with the nested-inherited-classes+alias-this hack, or by using interfaces+mixins. We agree at least that you have the same result with both right? Then, I guess is just a matter of taste. I simply find much more obscure and complex the nested-inherited-classes+alias-this hack than interfaces+mixins :)
 Scala supports that with mixins, D supports that with multiple
 subtyping.

I don't know what you mean about multiple subtyping. -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- I am so psychosomatic it makes me sick just thinking about it! -- George Constanza
Oct 03 2009
prev sibling next sibling parent Leandro Lucarella <llucax gmail.com> writes:
Andrei Alexandrescu, el  3 de octubre a las 12:03 me escribiste:
So, there we are, you have D, which doesn't support MI per se, you have to
hack it. You can do it with the nested-inherited-classes+alias-this hack,
or by using interfaces+mixins. We agree at least that you have the same
result with both right? Then, I guess is just a matter of taste. I simply
find much more obscure and complex the nested-inherited-classes+alias-this
hack than interfaces+mixins :)

I don't see using a nested class (or any class) with alias this as a hack. It's the way the whole thing is supposed to work in the first place.

Ok, then, I just find it ugly and unnecessary since you can do the same with interfaces+mixins. It's just a matter of personal preferences (as I said in my first mail), there is no point on arguing about it. =) -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ---------------------------------------------------------------------- I'll take a quiet life, a handshake of carbon monoxide, with no alarms and no surprises, no alarms and no surprises.
Oct 03 2009
prev sibling parent language_fan <somewhere internet.com.invalid> writes:
On Sat, 03 Oct 2009 13:52:51 -0300, Leandro Lucarella wrote:

 Scala supports that with mixins, D supports that with multiple
 subtyping.

I don't know what you mean about multiple subtyping.

I have also not seen the specs for this feature. How does multiple subtyping work exactly in D? Does it have exactly the same semantics as using interfaces + mixing in the traits? Why was the 'alias foo this' chosen if you are also planning to add support for Scala like traits (some other thread here recently discussed this). Andrei, you probably know how Scala chooses the overrides and overloads when traits have conflicts. How does D handle this?
Oct 03 2009