www.digitalmars.com         C & C++   DMDScript  

D - Multiple inheritance

reply "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
Sorry if this has come up before..

This was all looking good to me until I read one thing:

"D classes support the single inheritance paradigm, extended by adding
support for interfaces. "

For me this relegates D from the level of an improved and tidied up C++ down
to the level of Java - i.e. useful for some purposes but without the real
power and flexibility of C++. I'm sure some would disagree, but why was this
feature missed out of D? I can only assume that the designer(s) of D doesn't
use multiple inheritance themselves so decided it was superfluous. As RTTI
is part of the language (I assume this means all casts are effectively
dynamic_cast's), then I can't see a good reason for this other than wanting
to use the super() keyword to call the base class rather than specifying the
base class by name.

I've also just been reading about the lack of template support, which again
is a bit sad.

Dave
Jan 17 2002
parent reply "Pavel Minayev" <evilone omen.ru> writes:
"Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> wrote in
message news:a2698l$31fo$1 digitaldaemon.com...

 For me this relegates D from the level of an improved and tidied up C++
down
 to the level of Java - i.e. useful for some purposes but without the real
 power and flexibility of C++. I'm sure some would disagree, but why was
this And without bloat and complexity of C++, I must add... In most cases, interfaces are just enough where you'd use C++-style multiple inheritance. Some rare cases when it is really useful simply don't worth it, IMO. Remember the phrase from the D reference? "If a language can capture 90% of the power of C++ with 10% of its complexity, I argue that is a worthwhile tradeoff." I agree wholeheartedly.
 feature missed out of D? I can only assume that the designer(s) of D
doesn't
 use multiple inheritance themselves so decided it was superfluous. As RTTI
 is part of the language (I assume this means all casts are effectively
 dynamic_cast's), then I can't see a good reason for this other than
wanting Yes, all object casts are safe - they return null if type doesn't match (see cast.d - some info about internal structure of D classes can be borrowed from there).
 to use the super() keyword to call the base class rather than specifying
the
 base class by name.
You can do the latter as well, by the way =) "super" is simply a shorter form.
 I've also just been reading about the lack of template support, which
again
 is a bit sad.
Walter says templates will be in sooner or later. The compiler is still in too early stage to judge, anyhow.
Jan 17 2002
parent reply "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
"Pavel Minayev" <evilone omen.ru> wrote in message
news:a26fj0$3oi$1 digitaldaemon.com...
 "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> wrote in
 message news:a2698l$31fo$1 digitaldaemon.com...
 And without bloat and complexity of C++, I must add...
 In most cases, interfaces are just enough where you'd use C++-style
multiple
 inheritance. Some rare cases when it is really useful simply don't worth
 it, IMO.
Having spent the last 5 years working on a large project that uses multiple inheritance extensively I have to disagree ;-) But in this case there was a particular reason for it, it's not always that useful I agree.
Remember the phrase from the D reference?

     "If a language can capture 90% of the power of C++ with 10% of its
     complexity, I argue that is a worthwhile tradeoff."

 I agree wholeheartedly.
Okay - but I don't think that the lack of multiple inheritance makes the language any less complex, because if you don't need it you just don't use it. The only place multiple inheritence causes major problems is when you have diamond inheritence with virtual base classes, and I'd be happy for that to be left out. Dave
Jan 17 2002
parent reply "Walter" <walter digitalmars.com> writes:
"Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> wrote in
message news:a26h9g$5f5$1 digitaldaemon.com...
 Okay - but I don't think that the lack of multiple inheritance makes the
 language any less complex, because if you don't need it you just don't use
 it. The only place multiple inheritence causes major problems is when you
 have diamond inheritence with virtual base classes, and I'd be happy for
 that to be left out.
The "is multiple inheritance useful or just a bug" discussion goes back at least 10 years to when it was first proposed to be added to C++. The arguments have surged to and fro ever since <g>.
Jan 17 2002
parent reply "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a27dpc$pee$1 digitaldaemon.com...
 The "is multiple inheritance useful or just a bug" discussion goes back at
 least 10 years to when it was first proposed to be added to C++. The
 arguments have surged to and fro ever since <g>.
If multiple inheritance truly isn't useful, then why have it at all? You've taken the Java approach by being able to inherit from one class and several interfaces, which is kind of "multiple inheritance lite". I think most people will see how being able to inherit from multiple interfaces is useful, so why does anyone think that being able to inherit from multiple implementiations (or partial implementations) of those interfaces is not also useful? And as I said, if you don't want to use multiple inheritance then the fact that the language can do it won't get in your way. It just seems completely unnecessary to me. Surely one of the ways to improve on C++ is to make it more object oriented, not less. Dave
Jan 18 2002
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Dave Emberton wrote:

 If multiple inheritance truly isn't useful, then why have it at all? You've
 taken the Java approach by being able to inherit from one class and several
 interfaces, which is kind of "multiple inheritance lite". I think most
 people will see how being able to inherit from multiple interfaces is
 useful, so why does anyone think that being able to inherit from multiple
 implementiations (or partial implementations) of those interfaces is not
 also useful?

 And as I said, if you don't want to use multiple inheritance then the fact
 that the language can do it won't get in your way. It just seems completely
 unnecessary to me. Surely one of the ways to improve on C++ is to make it
 more object oriented, not less.
According to OOP theory, multiple inheritance is a good idea. But it's very difficult to pull off practically in a compiled language. The heart of the matter (to me) is that if we leave out multiple inheritance, the compiler will be simpler, smaller, less likely to have bugs (because it's easier to debug) and will be available sooner. From a technical sense, let me describe at the difficulties of MI. The first thing to remember is that a class is more or less just a structure with some compiler support that makes member function calls easy. Look at the following classes: class Foo { int i,j; int GetI() { return i; } int GetJ() { return j; } } class FooChild : Foo { int GetJ() { return 0; } } Note that there is one non-virtual member function and one virtual member function. The declaration above is somewhat like this C declaration: struct Foo { int i,j; struct { int (*GetJ)(struct Foo*); } vtable; } int Foo_GetI(struct Foo *this) { return this->i; }; int Foo_GetJ(struct Foo *this) { return this->j; }; struct FooChild { Foo parent_Foo; } int FooChild_GetJ(struct Foo *this) { return 0; }; When you create a "Foo" object, the compiler initializes the "vtable.GetJ" variable to point to "Foo_GetJ". When you create a "FooChild" object, it initializes "parent_Foo.vtable.GetJ" to point to "FooChild_GetJ". The beauty of this setup is that the parent Foo object is right at the beginning of the FooChild; thus any pointer to FooChild can be cast to a pointer to Foo without ever modifying the pointer. And since the Foo object is included whole within the FooChild, then the Foo REALLY IS there...with no special code needed, no changes required in Foo. Now consider what happens when you add a class Bar and derive Baz from Foo and Bar: class Bar { int i; int GetI() { return i*3; }; } class Baz : Foo, Bar { } Now, how do you implement this in C???? This is the closest I can come, but it's really ugly: struct Bar { int i; } int GetI(struct Bar *this) { return this->i*3; } struct Baz { Foo parent_Foo; Bar parent_Bar; } Now what does the compiler do when you try to call Baz::GetI()??? Or access Baz::i??? The answers are ambiguous unless you define complex rules for the language. Also, you can't cast a pointer to Baz to a pointer to Bar without modifying the pointer variable. Things get even worse when you have "diamond inheritance," where the same base class is included twice through two different children: class Fred : Foo {}; class Wilma : Foo {}; class Pebbles : Fred, Wilma {}; If you include two copies of Foo (the one that's part of Fred and the one that's part of Wilma), then you can't say that "Pebbles ISA Foo"...you say that "Pebbles INCLUDESA Foo (two of them)." But if you include only one copy of Foo, then you have screwed up the code in either Fred or Wilma. This is where C++ ends up having virtual classes and such. ugh. The beauty of the Java/D alternative is that you avoid all these complexities. Interfaces can be modeled as structures that are just lists of virtual function pointers. class Barney { int i; int GetI() { return i; } } class Betty { int j; int GetJ(); } interface BettyInt { int GetJ(); } class Bambam : Barney,BettyInt { // inherits i and GetI from Barney Betty betty; int GetJ() { return betty->GetJ(); } } Now this has a very workable implementation: struct Barney { int i; } int Barney_GetI(struct Barney *this) { return this->i; } struct Betty { int j; } int Betty_GetJ(struct Betty *this) { return this->j; } struct BettyInt { int (*GetJ)(void*); } struct Bambam { Barney parent_Barney; Betty betty; } int Bambam_GetJ(struct Bambam *this) { return Betty_GetJ(this->betty); } When you cast a pointer to Bambam into a pointer to Betty, it just takes the GetJ that Bambam has and stores that in the BettyInt. The beauty here is that the one object you inherit doesn't have ANY implementation changes, and the interface is defined from the very beginning to be nothing but a huge vtable. This vastly simplifies the compiler. Now, I'm not arguing that multiple inheritance is structurally bad...but it is difficult to implement for relatively little gain. -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jan 18 2002
next sibling parent reply "J. Daniel Smith" <j_daniel_smith deja.com> writes:
Yes.  As I understand Walter's reasoning, he's omitting "full" multiple
inheritence for practical reasons, not philisophical ones.  It's not about
whether or not multiple inheritence is useful, it's about developing a
language in which you stand a better chance of writing bug-free code and
having a compiler which correctly implements that language.

As can be seen from the C++ specification, getting all the details for
complete multiple inheritence specified is hard enough; but then you've got
to write a compiler which correctly implements all of that.  Everything is
much simplier with just multiple interface inheritence and combined with
aggregation/delegation you can usually get the job done.

Why add a feature that is really only absolutely required 10% of the time
and then is very difficult to get right?  If you really must have full
multiple inheritence, then C++ is the right tool to use.

   Dan

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C484184.758215B deming-os.org...
 Dave Emberton wrote:

 If multiple inheritance truly isn't useful, then why have it at all?
You've
 taken the Java approach by being able to inherit from one class and
several
 interfaces, which is kind of "multiple inheritance lite". I think most
 people will see how being able to inherit from multiple interfaces is
 useful, so why does anyone think that being able to inherit from
multiple
 implementiations (or partial implementations) of those interfaces is not
 also useful?

 And as I said, if you don't want to use multiple inheritance then the
fact
 that the language can do it won't get in your way. It just seems
completely
 unnecessary to me. Surely one of the ways to improve on C++ is to make
it
 more object oriented, not less.
According to OOP theory, multiple inheritance is a good idea. But it's
very
 difficult to pull off practically in a compiled language.  The heart of
the
 matter (to me) is that if we leave out multiple inheritance, the compiler
will
 be simpler, smaller, less likely to have bugs (because it's easier to
debug) and
 will be available sooner.



 From a technical sense, let me describe at the difficulties of MI.

 The first thing to remember is that a class is more or less just a
structure
 with some compiler support that makes member function calls easy.  Look at
the
 following classes:

 class Foo {
     int i,j;
     int GetI() { return i; }
     int GetJ() { return j; }
 }
 class FooChild : Foo {
     int GetJ() { return 0; }
 }

 Note that there is one non-virtual member function and one virtual member
 function.  The declaration above is somewhat like this C declaration:

 struct Foo {
     int i,j;
     struct {
        int (*GetJ)(struct Foo*);
     } vtable;
 }
 int Foo_GetI(struct Foo *this) { return this->i; };
 int Foo_GetJ(struct Foo *this) { return this->j; };
 struct FooChild {
     Foo parent_Foo;
 }
 int FooChild_GetJ(struct Foo *this) { return 0; };

 When you create a "Foo" object, the compiler initializes the "vtable.GetJ"
 variable to point to "Foo_GetJ".  When you create a "FooChild" object, it
 initializes "parent_Foo.vtable.GetJ" to point to "FooChild_GetJ".

 The beauty of this setup is that the parent Foo object is right at the
beginning
 of the FooChild; thus any pointer to FooChild can be cast to a pointer to
Foo
 without ever modifying the pointer.  And since the Foo object is included
whole
 within the FooChild, then the Foo REALLY IS there...with no special code
needed,
 no changes required in Foo.  Now consider what happens when you add a
class Bar
 and derive Baz from Foo and Bar:

 class Bar {
     int i;
     int GetI() { return i*3; };
 }
 class Baz : Foo, Bar {
 }

 Now, how do you implement this in C????  This is the closest I can come,
but
 it's really ugly:

 struct Bar {
     int i;
 }
 int GetI(struct Bar *this) { return this->i*3; }
 struct Baz {
     Foo parent_Foo;
     Bar parent_Bar;
 }

 Now what does the compiler do when you try to call Baz::GetI()???  Or
access
 Baz::i???  The answers are ambiguous unless you define complex rules for
the
 language.

 Also, you can't cast a pointer to Baz to a pointer to Bar without
modifying the
 pointer variable.  Things get even worse when you have "diamond
inheritance,"
 where the same base class is included twice through two different
children:
 class Fred : Foo {};
 class Wilma : Foo {};
 class Pebbles : Fred, Wilma {};

 If you include two copies of Foo (the one that's part of Fred and the one
that's
 part of Wilma), then you can't say that "Pebbles ISA Foo"...you say that
 "Pebbles INCLUDESA Foo (two of them)."  But if you include only one copy
of Foo,
 then you have screwed up the code in either Fred or Wilma.  This is where
C++
 ends up having virtual classes and such.  ugh.



 The beauty of the Java/D alternative is that you avoid all these
complexities.
 Interfaces can be modeled as structures that are just lists of virtual
function
 pointers.

 class Barney {
     int i;
     int GetI() { return i; }
 }
 class Betty {
     int j;
     int GetJ();
 }
 interface BettyInt {
     int GetJ();
 }
 class Bambam : Barney,BettyInt {
     // inherits i and GetI from Barney
     Betty betty;
     int GetJ() { return betty->GetJ(); }
 }

 Now this has a very workable implementation:

 struct Barney {
     int i;
 }
 int Barney_GetI(struct Barney *this) { return this->i; }
 struct Betty {
     int j;
 }
 int Betty_GetJ(struct Betty *this) { return this->j; }
 struct BettyInt {
     int (*GetJ)(void*);
 }
 struct Bambam {
     Barney parent_Barney;
     Betty betty;
 }
 int Bambam_GetJ(struct Bambam *this) { return Betty_GetJ(this->betty); }

 When you cast a pointer to Bambam into a pointer to Betty, it just takes
the
 GetJ that Bambam has and stores that in the BettyInt.  The beauty here is
that
 the one object you inherit doesn't have ANY implementation changes, and
the
 interface is defined from the very beginning to be nothing but a huge
vtable.
 This vastly simplifies the compiler.



 Now, I'm not arguing that multiple inheritance is structurally bad...but
it is
 difficult to implement for relatively little gain.

 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
Jan 18 2002
parent reply "Walter" <walter digitalmars.com> writes:
"J. Daniel Smith" <j_daniel_smith deja.com> wrote in message
news:a29hl2$ka6$1 digitaldaemon.com...
 Yes.  As I understand Walter's reasoning, he's omitting "full" multiple
 inheritence for practical reasons, not philisophical ones.  It's not about
 whether or not multiple inheritence is useful, it's about developing a
 language in which you stand a better chance of writing bug-free code and
 having a compiler which correctly implements that language.

 As can be seen from the C++ specification, getting all the details for
 complete multiple inheritence specified is hard enough; but then you've
got
 to write a compiler which correctly implements all of that.  Everything is
 much simplier with just multiple interface inheritence and combined with
 aggregation/delegation you can usually get the job done.

 Why add a feature that is really only absolutely required 10% of the time
 and then is very difficult to get right?  If you really must have full
 multiple inheritence, then C++ is the right tool to use.
That's essentially correct. MI is a major implementation effort, but adds only minor incremental functionality to the language. MI has been around for 10 years in C++, and 10 years of experience has not made a compelling case that it's really necessary. Single inheritance handles 90% of the cases, adding interfaces handles 90% of the rest. That leaves 1% <g>. Yes, I do understand that some folks really do like MI and require it for their own style of programming.
Jan 18 2002
parent "Juan Carlos Arevalo Baeza" <jcab roningames.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:a2a0f1$2q5j$1 digitaldaemon.com...
 "J. Daniel Smith" <j_daniel_smith deja.com> wrote in message
 news:a29hl2$ka6$1 digitaldaemon.com...
 Yes.  As I understand Walter's reasoning, he's omitting "full" multiple
 inheritence for practical reasons, not philisophical ones.  It's not
about
 whether or not multiple inheritence is useful, it's about developing a
 language in which you stand a better chance of writing bug-free code and
 having a compiler which correctly implements that language.

 As can be seen from the C++ specification, getting all the details for
 complete multiple inheritence specified is hard enough; but then you've
got
 to write a compiler which correctly implements all of that.  Everything
is
 much simplier with just multiple interface inheritence and combined with
 aggregation/delegation you can usually get the job done.

 Why add a feature that is really only absolutely required 10% of the
time
 and then is very difficult to get right?  If you really must have full
 multiple inheritence, then C++ is the right tool to use.
That's essentially correct. MI is a major implementation effort, but adds only minor incremental functionality to the language. MI has been around
for
 10 years in C++, and 10 years of experience has not made a compelling case
 that it's really necessary. Single inheritance handles 90% of the cases,
 adding interfaces handles 90% of the rest. That leaves 1% <g>.

 Yes, I do understand that some folks really do like MI and require it for
 their own style of programming.
The only thing I've really used MI for is mixins. And there are better ways to do them. For example: --- interface NamedObject { void name(int newname); int name(); } mixin MyMixin: NamedObject { char[] m_Name; void name(int newname) { m_Name = newname; } int name() { return m_Name; } } class MyClass { MyMixin; } --- Which the compiler re-arranges (macro-style) into: --- class MyClass: NamedObject { char[] m_Name; void name(int newname) { m_Name = newname; } int name() { return m_Name; } } --- That would be tremendously useful. It's very similar to the concept of "modules" in Ruby, only done at compile-time. Salutaciones, JCAB
Jan 18 2002
prev sibling parent reply "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3C484184.758215B deming-os.org...
 According to OOP theory, multiple inheritance is a good idea.  But it's
very
 difficult to pull off practically in a compiled language.  The heart of
the
 matter (to me) is that if we leave out multiple inheritance, the compiler
will
 be simpler, smaller, less likely to have bugs (because it's easier to
debug) and
 will be available sooner.
Okay - that's what we call engineering, and there's nothing wrong with that. But it seems a shame to limit a language because it would require more effort to write the compiler. The problems you mention have already been solved by C++ compilers, so it's not exactly impossible. No doubt the compiler would also be simpler if we left out contracts and unit tests and other features of D ;-) <snip>
 The beauty of this setup is that the parent Foo object is right at the
beginning
 of the FooChild; thus any pointer to FooChild can be cast to a pointer to
Foo
 without ever modifying the pointer.  And since the Foo object is included
whole
 within the FooChild, then the Foo REALLY IS there...with no special code
needed,
 no changes required in Foo.  Now consider what happens when you add a
class Bar
 and derive Baz from Foo and Bar:

 class Bar {
     int i;
     int GetI() { return i*3; };
 }
 class Baz : Foo, Bar {
 }

 Now, how do you implement this in C????  This is the closest I can come,
but
 it's really ugly:

 struct Bar {
     int i;
 }
 int GetI(struct Bar *this) { return this->i*3; }
 struct Baz {
     Foo parent_Foo;
     Bar parent_Bar;
 }

 Now what does the compiler do when you try to call Baz::GetI()???  Or
access
 Baz::i???  The answers are ambiguous unless you define complex rules for
the
 language.
If you mean that both Foo and Bar have GetI() then the same as C++ - causes a compiler error. I don't see how anyone would ever want it to try and work it out. If you mean that Foo doesn't have a GetI, then I guess what the compiler needs to do is something like: Bar* pBar=(Bar*)((char*)pBaz)+sizeof(Foo) Bar_GetI(pBar)
 Also, you can't cast a pointer to Baz to a pointer to Bar without
modifying the
 pointer variable.
True, but as all casts are dynamic_casts in D anyway, then a cast is never quite as simple as just using the same pointer value. Whatever mechanism makes that work must be able to make the multiple inheritance case work too.
 Things get even worse when you have "diamond inheritance,"
 where the same base class is included twice through two different
children: As I said, I'd be happy for the diamond inheritance to be left out as it really is a bad idea.
 Now, I'm not arguing that multiple inheritance is structurally bad...but
it is
 difficult to implement for relatively little gain.
True - but is the goal here to create a better language, or is the goal here to create a simpler compiler? From my point of view it's a shame that it's been left out, but I accept that others may have a completely different opinion. Dave
 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
Jan 18 2002
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Dave Emberton wrote:

 Okay - that's what we call engineering, and there's nothing wrong with that.
 But it seems a shame to limit a language because it would require more
 effort to write the compiler. The problems you mention have already been
 solved by C++ compilers, so it's not exactly impossible. No doubt the
 compiler would also be simpler if we left out contracts and unit tests and
 other features of D ;-)
But that's exactly the point - none (or very few) of the compilers ever got it all right! Rather than have a good standard, C++ is a mixmash of partially incompatible compilers. In truth, to get portable, reliable code, you pretty much have to dump most of the cooler features.
 If you mean that both Foo and Bar have GetI() then the same as C++ - causes
 a compiler error. I don't see how anyone would ever want it to try and work
 it out.
My memory is that actually it *is* possible. If both GetI's are declared as virtual functions, then it is legal. Or do you only have to declare one of them virtual? If so, which one? The point is, very few people know what the standard actually is enough to be able to use it.
 As I said, I'd be happy for the diamond inheritance to be left out as it
 really is a bad idea.
Since *all* classes in D are derived from Object, then every instance of multiple inheritance has to deal with diamon inheritance. :(
 Now, I'm not arguing that multiple inheritance is structurally bad...but
it is
 difficult to implement for relatively little gain.
True - but is the goal here to create a better language, or is the goal here to create a simpler compiler? From my point of view it's a shame that it's been left out, but I accept that others may have a completely different opinion.
I'm just not convinced that MI gives you a better language. But I am convinced that having partially-conforming, partially incompatible compilers gives you a worse language. So it seems that MI and stuff like that would be risking almost certain downsides against very small upsides. Now, OTOH, I'm not against defining a separate standard of some sort that takes a language much like D (but uses MI) and translates it down to D. That might be workable, and could almost certainly be written in a portable script format like PERL or something. Maybe we can call it D++ :) -- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jan 18 2002
prev sibling parent reply la7y6nvo shamko.com writes:
"Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:

 If multiple inheritance truly isn't useful, then why have it at all? You've
 taken the Java approach by being able to inherit from one class and several
 interfaces, which is kind of "multiple inheritance lite". I think most
 people will see how being able to inherit from multiple interfaces is
 useful, so why does anyone think that being able to inherit from multiple
 implementiations (or partial implementations) of those interfaces is not
 also useful?
I think there is general agreement that multiple inheritance is (which is to say, can be) useful. The question is, does multiple inheritance add enough utility to make it worth the cost of extra complexity in the language? It's hard to make a compelling case for multiple inheritance; perhaps one will be made, but I'm not aware of any example having been put forth. And I know of no study that's been done that tries to measure the cost of having multiple inheritance in a language.
 And as I said, if you don't want to use multiple inheritance then 
 the fact that the language can do it won't get in your way. 
This idea - that one can ignore language features one doesn't use - is an old one, going back at least to the 1960's, but unfortunately it isn't right. The problem is, if multiple inheritance is there, someone (in fact lots of someones) will use it. Unless you're in the position of not working with other programmers, not working on code that other people write, not using any third party software, and not using any standard libraries, you almost certainly *are* going to encounter code that uses multiple inheritance, and then you'll no longer be able to ignore its presence. So I think the idea that language features can be used by people who want them and ignored by people who don't just isn't convincing.
Jan 24 2002
parent reply Russell Borogove <kaleja estarcion.com> writes:
la7y6nvo shamko.com wrote:

 "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
And as I said, if you don't want to use multiple inheritance then 
the fact that the language can do it won't get in your way. 
This idea - that one can ignore language features one doesn't use - is an old one, going back at least to the 1960's, but unfortunately it isn't right. The problem is, if multiple inheritance is there, someone (in fact lots of someones) will use it. Unless you're in the position of not working with other programmers, not working on code that other people write, not using any third party software, and not using any standard libraries, you almost certainly *are* going to encounter code that uses multiple inheritance, and then you'll no longer be able to ignore its presence. So I think the idea that language features can be used by people who want them and ignored by people who don't just isn't convincing.
That seems like a bogus argument. If a library designer feels that multiple inheritance is important, that library designer is going to work in a language that supports it. If you and your coworkers can't agree on an acceptable language subset, you have worse problems than having to learn the perils of multiple inheritance.[1] In the particular case of MI, it seems pretty easy to ignore it even if some library class you're using uses it. The library can do its little MI dance, you can singly inherit from those library classes. If the library doesn't work right it's someone else's problem to understand and fix. To say otherwise is to make a case against using any middleware or third-party code in general, which is a separate discussion entirely. -Russell B [1] In 1994, I had to rewrite a nice chunk of code because my project lead wasn't comfortable with C++, and believed, or claimed to believe, that merely using classes -- without any virtual functions -- had unacceptable performance overhead. The team agreed to avoid C++, my code was rewritten, and I eventually quit.
 
 
Jan 24 2002
next sibling parent "Walter" <walter digitalmars.com> writes:
"Russell Borogove" <kaleja estarcion.com> wrote in message
news:3C50E255.6020301 estarcion.com...
 [1] In 1994, I had to rewrite a nice chunk of code because my
 project lead wasn't comfortable with C++, and believed, or
 claimed to believe, that merely using classes -- without any
 virtual functions -- had unacceptable performance overhead.
 The team agreed to avoid C++, my code was rewritten, and I
 eventually quit.
The solution there is easy - just run your C++ code through Cfront! Voila! It's now in C! You've all seen my complaints about C++, but performance of the resulting code isn't one of them. I've been careful in the design of D to not define behavior that mandates inefficient code generation. I still write most code on a 200 Mhz Pentium. Why not upgrade to a 1.7Ghz machine? Because it keeps my attention focussed on writing fast executing code. The only time I really miss a faster machine is when running the test suites, which take hours.
Jan 24 2002
prev sibling parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Russell Borogove" <kaleja estarcion.com> wrote in message
news:3C50E255.6020301 estarcion.com...
 la7y6nvo shamko.com wrote:

 "Dave Emberton" <demberton-nospam nospam.digitalworkshop.com> writes:
And as I said, if you don't want to use multiple inheritance then
the fact that the language can do it won't get in your way.
This idea - that one can ignore language features one doesn't use - is an old one, going back at least to the 1960's, but unfortunately it isn't right. The problem is, if multiple inheritance is there, someone (in fact lots of someones) will use it. Unless you're in the position of not working with other programmers, not working on code that other people write, not using any third party software, and not using any standard libraries, you almost certainly *are* going to encounter code that uses multiple inheritance, and then you'll no longer be able to ignore its presence. So I think the idea that language features can be used by people who want them and ignored by people who don't just isn't convincing.
That seems like a bogus argument. If a library designer feels that multiple inheritance is important, that library designer is going to work in a language that supports it. If you and your coworkers can't agree on an acceptable language subset, you have worse problems than having to learn the perils of multiple inheritance.[1]
exactly why the argument for implementing X because language features that can be ignored is flawed, a sound argument for not implementing X.
 In the particular case of MI, it seems pretty easy to ignore
 it even if some library class you're using uses it. The library
 can do its little MI dance, you can singly inherit from those
 library classes. If the library doesn't work right it's someone
 else's problem to understand and fix. To say otherwise is to
 make a case against using any middleware or third-party code in
 general, which is a separate discussion entirely.
then problem with MI in C++ is you get two types of inheritance Single Inheritance of one of the classes and containment of the others class B {}; class D :public B {}; you can pass D as a B and then get it back to a D but class A {}; class B {}; class D :public A,B {}; you can pass D as A or B, but only the A can be cast back to D, in C++ MI is realy just SI with cheap syntax for containment and automatically generated overloaded cast/pointer operations. C++ has a real headache even with virtual inheritance because the this pointer can not change if it did you would lose access to parts of you object. so you have to fully populate your Vtable. virtual inheritance, is saying lets add a member to my class that pointer to the location of my superclass does not solve the over all problem that casting can change the reference/pointer. Java has interfaces, to give light weight MI, it only allows virtual functions becuase of the way it works, it could have been made to work for member too. you still have to look to find out where in your object you "interface" is some method of allowing disimilar object to have an identical interface is required but full blown MI has too many nasties under the surface. not only is it a headache for the compiler writer is can be IMHO more work for the designer if you have to work with libraries that use it, than working out a design that does not require it. Mike.
Jan 25 2002