why C# can't support multiple inheritance?

  • Thread starter Thread starter Matthew Louden
  • Start date Start date
Hung Jung Lu said:
Erh? You got the direction wrong. It's not down the tree, it's up the
tree.

Depends which direction the tree is pointing ;-)
Secondly, in Mix-In class methods, you do not want to access parent
data fields, you want to access child data fields. That's the beauty
of it. I guess you just jumped in without having read my points about
virtual data fields.

I read it, but your context got lost in the noise of the other posts.
Ask yourself: how can a parent class method access the data fields of
a child class? A first answer is: you CAN'T. When you designed the
parent class, you had zero information about the child class. In
statically typed languages like C++/Java/C#, there is simply no way of
accessing child data fields directly. These languages don't support
virtual data fields.

Correct, because these languages abide by the tenet that while it's cheap to
access a field of a different type, you should only directly access a field
of your own type, which prevents inadvertant and unwanted value updates and
reads that can cause issues with the implementation details of the other
type. This, in my opinion, is the biggest risk with multiple inheritance
(and as I said, i'm not entirely opposed to MI either).
So far so good for C++, until you are hit with absence of MI class
inheritance in C#/Java. You then scratch your head and ask yourself:
"How in the world can I write a Mix-In class?"

If you abide by the basic definition of a Mix-In class, which is an abstract
class designed to be blended with another type through MI in order to extend
its members, then I think you will find it isn't such a stretch after all.
That in fact, Mix-In classes are just syntactical sugar for alternate
structural mechanisms.
Well, you can still do it. If the Mix-In class B is specifically
designed to enhance an existing class A, your methods in B can take
instance of A as the first argument. You then do
containment+delegation to expose the B interface for the new class.
Yep.

All these things are voodoo magic in C#/Java. (And I am sure I have
lost 95% of the audience.) But in dynamically typed languages like
Python or Ruby, these are banalities not even worth a discussion.
Sure, under the hood they are quite equivalent. But in C#/Java you (a
human) are basically doing the job that a good compiler (a machine)
should do.

While I don't disagree with you, I think the underlying principal is that
the designers of these languages came to the conclusion that the "good
compiler" is allowing programmers to do things that perhaps shouldn't be
done, or at the very least create a recipe for danger too easily. Whether
one agrees with that decision or not is a matter of personal opinion.
Personally, I think there are far better uses for MI than Mix-In classes,
but in the C#/Java world, we simply have to live without it. Now, having had
to maintain programs that were falling apart at the seams because of
convoluted inheritance trees, I can understand the concern, though I haven't
completely decided that I agree 100% or not with the language designers -
especially since, if you forget the gritty internal details and think about
the overall design structure, there certainly are ways to still accomplish
the underlying goals.
After you are laboriously and happily done with using class MI and
factoring out the common code spots of your program, you would
probably cry again when you need to make changes. MI is just too hard
to use directly.

Yes. And therein lies a good deal of the pain :-)
The test of any object model is it's ability to be maintained and extended
AFTER the initial implementation, and MI *can* easily cause that to collapse
quickly. Note that I said *can* because some people insist on preaching that
MI is evil, like it's guaranteed to break things, and I'm certainly not
advocating that line of thought.
In C#/Java, a better approach is to use a code
generator, and just let the common code spread all over different
classes. Sure, this is code bloating (much like templates in C++,
which are just macros). But given the shortcomings of C#/Java, you
don't have much a choice.

Hm, I'm not entirely convinced that's the only choice. And having lived with
deficient code generators before, I'll take my chances with something else
(even if it is a little more manual) :-)
But on the flipside, I can honestly say that I haven't gone through
withdrawl over the lack of MI either.

-Rob Teixeira [MVP]
 
Going back to the original poster - this debate is the perfect illustration
as to why MI is not in the CLR.

True, but there are ways to resolve this. Still the issue remains and cannot
be covered. There is complexity.

I grant that there is complexity when using C++ and MI. But in my opinion,
you have apparently *only* used MI in C++. If you have never used a language
that properly implements MI, it is going to be very very difficult for you
to convince me that my experience with Eiffel's MI is incorrect. Let me put
it this way - MI is so easy to use in Eiffel that there are *no* non-trivial
Eiffel systems that fail to use it. It's one of the core idioms in the
standard libraries. It is taught very early in the official Eiffel hands-on
course. Experience with Eiffel as a teaching language shows that MI (in
Eiffel anyway) is really not a difficult concept to grasp and leverage.

Now, the question is - if Eiffel can do it correctly, why is it that *you*
think it's a general OO problem, rather than a language issue? I think the
C# language and CLR teams are smart enough to see what works and what
doesn't, and if they do implement MI, I'm hoping that it looks more like the
Eiffel model than the C++ model.
 
But in my opinion,
you have apparently *only* used MI in C++
You are spot on there. But according to stroustrup, that's where C++
borrowed inheritance from anyway. Vulcan logic dictates that either
complexity was added in. OR, it's implementation was complex to start with.
I've never worked with eiffel, so i'll take your word for it that it is
trivial implemented though having used it in C++ it seems contrary since
that is where it came from.
If you have never used a language
that properly implements MI,
Again, the C++ bashing. Why do you think it isn't properly implemented? It
works well for those who care enough to understand how to use it. Most
people do not spend the time to understand MI. Couple that with poor
application design, and MI becomes a mess. But you cannot lay blame on C++
for that? Or is that what you are suggesting?
Now, the question is - if Eiffel can do it correctly, why is it that *you*
think it's a general OO problem, rather than a language issue?
That wasn't me. What I said was

"this is a function of the language, not MI implementation. MI has to sit
within the bounds of the underlying language. If that language syntax is
overly complex then MI implementation cannot be simple."

I'm willing to let that misquote slide
 
Back
Top