digitalmars.D - Suggestion: Allow Multiple Inheritance and still preserver super() functionality
- Jim Gadrow (58/58) Mar 06 2008 Now, maybe I'm just ignorant because I've never written a compiler, but ...
- Russell Lewis (39/113) Mar 06 2008 Funny, just yesterday my professor gave a lecture on "why multiple
- Mike Parker (8/11) Mar 06 2008 The term 'superclass' is more common in the OOP vernacular than 'parent
- Scott S. McCoy (5/20) Mar 07 2008 Another issue with Multiple Inheritance is that in practice multiple
- Simen Kjaeraas (35/46) Mar 08 2008 =
- Jim Gadrow (2/2) Mar 07 2008 Thank you all for your responses. They have illuminated why multiple-inh...
- Steven Schveighoffer (29/36) Mar 07 2008 There are ways to do it with inner classes (without solving the diamond
Now, maybe I'm just ignorant because I've never written a compiler, but why isn't it possible to allow for something like the example following in the language? I will first state that I don't like the super() function because I don't believe the keyword 'super' very clearly identifies what is going on. wouldn't parent() have been more suitable? Anyways, the example: import std.stdio; interface A { void myFoo (); } interface B { void myBar (); } class C : A { this () { writefln ("Constructing a C..."); } void myFoo () { writefln ("I've been foo'd!"); } } class D : B { this () { writefln ("Constructing a D..."); } void myBar () { writefln ("I've been bar'd!"); } } class E : C, D { this () { parent.C (); //Calls constructor of parent class C parent.D (); //Calls constructor of parent class D } void myFooBar () { myFoo (); myBar (); } } void main () { E myClass; myClass.myFooBar (); } Running the program should output: Constructing a C... Constructing a D... I've been foo'd! I've been bar'd! Obviously, the same rule would apply for inheriting multiple classes as for inheriting multiple interfaces in that something like: class D : C, C Would cause a compile error.
Mar 06 2008
Funny, just yesterday my professor gave a lecture on "why multiple inheritance seems like a good idea but is really hard to make work in practice." (I'm in graduate school.) The problem with MI isn't a syntax problem; there are a series of fundamental problems that are very hard to solve. First is the "Diamond Problem," which I won't discuss here because Wikipedia has a good page on it: http://en.wikipedia.org/wiki/Diamond_problem Another problem has to do with the binary layout of classes. With single inheritance, you can define the binary layout of a class, and then require that any of its descendants preserve that layout. That is, if you have class A { int x; } class B : A { int y; } Then the binary layout of B is: +--------------------------+ | exact copy of A's fields | +--------------------------+ | new B fields | +--------------------------+ This makes it possible to convert a pointer-to-B to a pointer-to-A (and vice-versa) without any complexity or rewriting; it just works. This is particularly important for methods, which the child might override, since you can call the methods using a pointer-to-A. The calling function can pass the pointer-to-A as the implicit "this" pointer without knowing that the called function will interpret this as a pointer-to-B. This works elegantly because the two pointers have the same binary representation. Problem is, if a class has two parents, then you can't make that assumption. You could include both of the parents whole, by value, but then you can't solve the diamond problem, and also you can't call overridden functions (because the "this" pointer for one of the parents is different than the "this" pointer of the child). You can solve this, but it's costly in terms of language complexity and runtime performance. Experience has shown that single-inheritance-with-interfaces is a much more practical solution for C-family languages. Russ Jim Gadrow wrote:Now, maybe I'm just ignorant because I've never written a compiler, but why isn't it possible to allow for something like the example following in the language? I will first state that I don't like the super() function because I don't believe the keyword 'super' very clearly identifies what is going on. wouldn't parent() have been more suitable? Anyways, the example: import std.stdio; interface A { void myFoo (); } interface B { void myBar (); } class C : A { this () { writefln ("Constructing a C..."); } void myFoo () { writefln ("I've been foo'd!"); } } class D : B { this () { writefln ("Constructing a D..."); } void myBar () { writefln ("I've been bar'd!"); } } class E : C, D { this () { parent.C (); //Calls constructor of parent class C parent.D (); //Calls constructor of parent class D } void myFooBar () { myFoo (); myBar (); } } void main () { E myClass; myClass.myFooBar (); } Running the program should output: Constructing a C... Constructing a D... I've been foo'd! I've been bar'd! Obviously, the same rule would apply for inheriting multiple classes as for inheriting multiple interfaces in that something like: class D : C, C Would cause a compile error.
Mar 06 2008
Jim Gadrow wrote:I will first state that I don't like the super() function because I don't believe the keyword 'super' very clearly identifies what is going on. wouldn't parent() have been more suitable?The term 'superclass' is more common in the OOP vernacular than 'parent class', so super() is spot on, IMO. You'll find the same used in Java and probably some other languages. Using 'parent()' would almost certainly cause some consternation among some D users, since the terms 'parent' and 'child' are often used to describe relationships in data structures. It's not uncommon to see methods like parent() (or getParent()) to fetch a parent node in a tree.
Mar 06 2008
On Fri, 07 Mar 2008 12:40:54 +0900, Mike Parker wrote:Jim Gadrow wrote:Another issue with Multiple Inheritance is that in practice multiple inheritance is often unnecessary and rarely used correctly. More often than not, it's bastardized and used as a form of consuming dependencies as opposed to actually specifying inherent relationships.I will first state that I don't like the super() function because I don't believe the keyword 'super' very clearly identifies what is going on. wouldn't parent() have been more suitable?The term 'superclass' is more common in the OOP vernacular than 'parent class', so super() is spot on, IMO. You'll find the same used in Java and probably some other languages. Using 'parent()' would almost certainly cause some consternation among some D users, since the terms 'parent' and 'child' are often used to describe relationships in data structures. It's not uncommon to see methods like parent() (or getParent()) to fetch a parent node in a tree.
Mar 07 2008
On Fri, 07 Mar 2008 04:40:54 +0100, Mike Parker <aldacron71 yahoo.com> = wrote:Jim Gadrow wrote:=I will first state that I don't like the super() function because I =ng =don't believe the keyword 'super' very clearly identifies what is goi=t =on. wouldn't parent() have been more suitable?The term 'superclass' is more common in the OOP vernacular than 'paren=class', so super() is spot on, IMO. You'll find the same used in Java ==and probably some other languages. Using 'parent()' would almost certainly cause some consternation among==some D users, since the terms 'parent' and 'child' are often used to =describe relationships in data structures. It's not uncommon to see =methods like parent() (or getParent()) to fetch a parent node in a tre=e. In Object Pascal, the keyword for calling methods from the parent (super= ) = class is 'inherited'. //------- Foo =3D class procedure doStuff(); end; Bar =3D class(Foo) procedure doStuff(); overload; end; ... procedure Foo.doStuff(); begin // code here end; procedure Bar.doStuff(); begin inherited(); inherited doStuff(); // equivalent to above line, calls parent.doStuf= f(); // code here end; //------- I'm not saying I'm for including 'inherited' in D - 'super' fits me = perfectly. It may be clearer what it does than 'super' or 'parent', thou= gh. -- Simen
Mar 08 2008
Thank you all for your responses. They have illuminated why multiple-inheritance is less than optimal in terms of language implementation. The only thing I will miss is the ability to allow a class to inherit fields from multiple classes if it 'is' related to both classes. But, I suppose I could do that via mixin, it just seems to add work-around code but at least now I know the rationale behind it.
Mar 07 2008
"Jim Gadrow" wroteThank you all for your responses. They have illuminated why multiple-inheritance is less than optimal in terms of language implementation. The only thing I will miss is the ability to allow a class to inherit fields from multiple classes if it 'is' related to both classes. But, I suppose I could do that via mixin, it just seems to add work-around code but at least now I know the rationale behind it.There are ways to do it with inner classes (without solving the diamond problem): class A { void a() {} } class B { void b() {} } class C : A { void a() {} class innerB : B { void b() { // can call a() or access C's members} C opCast() { return this.outer; } } // make it seamless private innerB _innerB; void b() { _innerB.b() } B opCast() { return _innerB;} } This really is just exposing the ugliness that compilers that support multiple inheritance hide :) But I'd say before doing something like this, the best thing to do is to try and use interfaces and encapsulation. -Steve
Mar 07 2008