Multiple base classes in .NET

B

Ben Voigt [C++ MVP]

On the other hand, ATL does all its business with template tricks and
doesn't use the virtual function call mechanism very much, if at all.
(I can't recall right now if it uses any virtual functions or not, but
my recollection is that I don't recall any virtual function business
going on when I last studied the ATL Internals book.)


LOL

COM is built on a function dispatch table... in C++ parlance, a v-table.

Now, the implementation might not call those virtual functions
polymorphically, but ATL projects are full of virtual functions.
 
B

Ben Voigt [C++ MVP]

The basic behaviors that MI allow still exist in .NET. They just require
writing a little more code, while at the same time avoiding some of the

"Just require writing a little more code" = increased maintenance burden.
pitfalls that true MI creates.

No, because all the pitfalls that MI creates are now left to the programmer
to handle manually (i.e. MI member lookup has compiler assist which might
have an ambiguity, in .NET the programmer must explicitly list which method
is being called. And the consumer is still faced with ambiguity, as stated
earlier.)
 
R

Richard

[Please do not mail me a copy of your followup]

"Ben Voigt [C++ MVP]" <[email protected]> spake the secret code
Sorry, but generics aren't templates, and you can't "do template type
tricks".


For instance, that line won't work with generics.

Interesting! OK, I didn't know that.
 
R

Richard

[Please do not mail me a copy of your followup]

"Ben Voigt [C++ MVP]" <[email protected]> spake the secret code
LOL

COM is built on a function dispatch table... in C++ parlance, a v-table.

COM, yes, but the mechanisms that ATL uses to implement itself are
built around templates and not virtual functions, IIRC.
 
Z

Zachary Turner

Mark Rae said:
"Larry Smith" <no_spam@_nospam.com> wrote in message

[Multiple Inheritence]

That's just... not right.

The entire STL is full of multiple inheritence. Every C++ programmer's first
program uses it, even if they're not aware of it (IOStream).

It certainly isn't "full of multiple inheritance". You gave one
example, and I don't think there's another. Multiple inheritance is
extremely unintuitive, hard to work with, and 99 times out of 100 it
is indicative of a bad design. 1 time out of 100 maybe you've got
something great with multiple inheritance, but one of the fundamental
philosophies of .NET is to err on the side of safety. Having been a C+
+ programmer for over 10 years, I'm praying multiple inheritance
doesn't ever see the light of day in .NET. Even single inheritance is
abused more often than not, when containment would be a much better
solution.
 
C

Chris Mullins [MVP]

Actually, it is. I've worked for many different companies, both large and
small, and almost everybody uses it. I find it very hard to believe this
isn't the norm.

In all honesty, I've used it quite a bit, and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

With .Net, it's especilly frustrating, as your inheritence tree is often
dictated to you by the platform. With my inheritence tree defined (web page,
control, EnterpriseComponet, or whatever), adding my my own behavior means
alot of mindless (and often silly) code duplication. Some of this is
mitigated in .Net 3.5, with Extension Methods, but by no means all of it.
I didn't say it wasn't powerful. The mechanics get progressively more
difficult to work with however as class hiearchies become non-trivial.

The exact same can be said of dozens of technologies:
- Threading technologies.
- Dynamic Code Generation.
- Operator Overloading

Any of these can be, and often are, badly abused.

VB 1-6 didn't have any of them, and the world got along just fine. Tons of
code was written. Obviously they're not needed at all. Clearly this means
even inheritence isn't required, as developers (as Microsoft document from
that era made very, very clear) often screw it up, and Interfaces are a far
superior technology.
You must have precious little experience dealing with large class
hierarchies then..

Yeeeea. That's what it is. :)
When you factor in issues like virtual base classes, the calling of their
constructors from the most dervied class (which refutes your claim that
MI is widely used since very few C++ programmers even know about this),
the headaches involved with ambiguity (a major pain), etc., then it
becomes a major deterrent very quickly unless your class hierarchies
remain trivial.

I'm afraid I don't follow your logic.

The classic MI "Dreaded Diamond Pattern" is certainly on the "don't do this"
list, and need to be worked around with good design. All of the C++ guys
I've worked with have either been aware of this, or quickly been made aware
of it by their peers. I don't see how this changes anything - all of the
advanced technologies have drawbacks that can be, and often are, abused.

For example, threading. Where do you do locking and synchronization? What
thread context is your method running on? Can you access these other classes
or do you need to lock? Are there others calling you from inside a lock - if
so, that database call you're about to make is a really bad idea). Unless
your class hierarchy is trival, these are really hard question. Much harder,
in my opinion, than solving the MI Diamond issues.

For example, anything distributed. Where are you running? In what context?
Is there a network between you and your processor? Should you build chatty
or chunky methods? Can you call this other class at all?

The list goes on....

I'm fine requiring users to take MCP exam 70-666 (Multiple Interitence),
which gives them a key they can put into their compilers to unlock MI.
 
R

Richard

[Please do not mail me a copy of your followup]

"Chris Mullins [MVP]" <[email protected]> spake the secret code
In all honesty, I've used [multiple inheritance] quite a bit,
and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

So how do you feel about "Design Patterns" saying you should prefer
aggregation over inheritance?
 
C

Chris Mullins [MVP]

Richard said:
Chris Mullins said:
In all honesty, I've used [multiple inheritance] quite a bit,
and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

So how do you feel about "Design Patterns" saying you should prefer
aggregation over inheritance?

I would feel alot better about aggregation if it were better supported by
the language.

If there was an attribute I could use:

[Aggregatable]
public class Point
{
int x; int y;
}

public class Circle
{
[Aggrigates(type=Single)] Point;
int Radius;
}

This code would:
1 - Automatically create an interface (IPoint) (or even an Anonymous Type)
2 - Automatically turn Circle into "Circle : IPoint"
3 - Automatically wire up "Circle.X" & "Circle.Y"

I would love to see a 1:Many aggrigation attribute as well:
public class VectorField
{
[Aggrigates(type=Collection)] Vector;
}

This would automatically:
1 - Turn VectorField into "VectorField : IList<Vector>"
2 - Implement all the various IList<Vector> code for me

Even more fun would be:
public class TensorField
{
[Aggrigates(type=Dictionary<Vector>)] Tensor;
}

This would automatically:
1 - Turn TensorField into "TensorField:IDictionary<Vector, Tensor>"
2 - Implement all the various IDictionary<Vector,Tensor> code for me

As it sits, aggregation (to me) means, "Write a whole lot of wrapper code to
wire up the various methods". In general though, in .Net I over-use
aggrigation simply becuase with single inheritence, there's no choice.
 
R

Richard

[Please do not mail me a copy of your followup]

"Chris Mullins [MVP]" <[email protected]> spake the secret code
Richard said:
Chris Mullins said:
In all honesty, I've used [multiple inheritance] quite a bit,
and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

So how do you feel about "Design Patterns" saying you should prefer
aggregation over inheritance?

I would feel alot better about aggregation if it were better supported by
the language.

I think you missed the point of my question. Design Patterns was
written long before .NET was even an idea at Microsoft. DP isn't
about languages or syntactic sugar. In this case "prefer aggregation
over inheritance" is not saying never to use inheritance, nor is it
saying always use aggregation, but it is saying prefer one over the
other.

You seem to be expressing the exact opposite preference. DP goes
beyond issuing a simple aphorism and goes into the details of why
aggregation should be preferred over inheritance.

Beyond your simple personal preference, what are the reasons for
preferring multiple inheritance over single inheritance?

If even single inheritance is to be less preferred over aggregation,
then the case would seem to be even stronger against multiple
inheritance.
 
C

Chris Mullins [MVP]

Richard said:
Beyond your simple personal preference, what are the reasons for
preferring multiple inheritance over single inheritance?

My reason is very simple:
Every now & then, I run across problems that are best solved though MI. This
seems to happen with about the same frequency I run across a problem that's
best solved by me creating a new thread. (e.g. every few weeks).

In the MI case, I can work around it. Interfaces & aggrigation allows for
this. It just means I have to write more code - sometimes a good deal more
code.

To me, the evolution of a platform means I write less code, especially for
common use cases. The less code that I write, the less likley that I am to
have bugs in my code.
If even single inheritance is to be less preferred over aggregation,
then the case would seem to be even stronger against multiple
inheritance.

I'm fine (and agree with!) with the argument for MI being "Perfer SI over
MI.".

That's a far cry from "Never use MI!", which is something I don't agree
with.

When I give presentations on concurrency, my logic is:
1 - Prefer Async Methods over anything else
2 - Prefer ThreadPool threads over custom threads.
3 - Prefer Timers & Background workers over custom threads.

.... at the very bottom of the list is, "If you really, really, must, go
ahead and create your own thread.".

This is a far cry from "Remove Custom Threads from the Platform!".
 
F

Frank Hileman

Hello,

Let me explain why I miss multiple inheritance.

Consider the following situation. Your class has a property X with a simple
field backing the property, with limited behavior -- all behavior is
independent of other properties. For design-time support you decorate this
property with several attributes, and add ShouldSerializeX and ResetX
methods.

Now to duplicate this property in another class, that has a different base
class (cannot share via inheritance) you must copy the field, all the code,
and the attributes. This is not a big deal with one property, but multiply
it by 20 or so properties and several classes, and you realize it is a
maintenance problem.

Interfaces don't help. An interface only helps when you need to use the
property, allowing you to avoid special casing for each class.

Delegation (aggregation) does not help either, because the code duplication
is at the surface level.

With mixin support in C#, we could create a mixin class for those
properties, and the code duplication is eliminated. If the mixin class does
not share any base classes with the "mixed" classes, there are none of the
usual diamond inheritance problems.

Consider scala's support for mixins as a good model for .net:
http://www.scala-lang.org/intro/mixin.html

Whether or not someone needs mixins depends on their task. Some domain
abstractions can be cleanly broken down into a strict hierarchy. Other
things are less hierarchical by nature and work poorly that way. So I don't
think anyone should claim no one needs mixins, or everyone needs mixins.

Personally I have needed mixins on a recent project and have wound up
pushing lots of members up the hierarchy, into base classes, when I would
prefer not to, just to avoid the pain of delegation.

Let me see if I can explain the motivation behind suggestion, "prefer
aggregation over inheritance". If you only use single inheritance, you are
limited by the type hierarchy. Additionally, multiple inheritance has
problems in some languages.

Those problems do not arise with good mixin support. Mixins can work better
than aggregation for code reuse, and mixin code reuse is not limited by the
type hierarchy. So "prefer aggregation over inheritance" is a reflection of
the languages used (probably c++).

Regards,
Frank Hileman

check out VG.net: http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio graphics editor

Richard said:
[Please do not mail me a copy of your followup]

"Chris Mullins [MVP]" <[email protected]> spake the secret code
Richard said:
"Chris Mullins [MVP]" <[email protected]> spake the secret code
In all honesty, I've used [multiple inheritance] quite a bit,
and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

So how do you feel about "Design Patterns" saying you should prefer
aggregation over inheritance?

I would feel alot better about aggregation if it were better supported by
the language.

I think you missed the point of my question. Design Patterns was
written long before .NET was even an idea at Microsoft. DP isn't
about languages or syntactic sugar. In this case "prefer aggregation
over inheritance" is not saying never to use inheritance, nor is it
saying always use aggregation, but it is saying prefer one over the
other.

You seem to be expressing the exact opposite preference. DP goes
beyond issuing a simple aphorism and goes into the details of why
aggregation should be preferred over inheritance.

Beyond your simple personal preference, what are the reasons for
preferring multiple inheritance over single inheritance?

If even single inheritance is to be less preferred over aggregation,
then the case would seem to be even stronger against multiple
inheritance.
 
Z

Zachary Turner

Hello,

Let me explain why I miss multiple inheritance.

Consider the following situation. Your class has a property X with a simple
field backing the property, with limited behavior -- all behavior is
independent of other properties. For design-time support you decorate this
property with several attributes, and add ShouldSerializeX and ResetX
methods.

Now to duplicate this property in another class, that has a different base
class (cannot share via inheritance) you must copy the field, all the code,
and the attributes. This is not a big deal with one property, but multiply
it by 20 or so properties and several classes, and you realize it is a
maintenance problem.

Interfaces don't help. An interface only helps when you need to use the
property, allowing you to avoid special casing for each class.

Delegation (aggregation) does not help either, because the code duplication
is at the surface level.

With mixin support in C#, we could create a mixin class for those
properties, and the code duplication is eliminated. If the mixin class does
not share any base classes with the "mixed" classes, there are none of the
usual diamond inheritance problems.

Consider scala's support for mixins as a good model for .net:http://www.scala-lang.org/intro/mixin.html

Whether or not someone needs mixins depends on their task. Some domain
abstractions can be cleanly broken down into a strict hierarchy. Other
things are less hierarchical by nature and work poorly that way. So I don't
think anyone should claim no one needs mixins, or everyone needs mixins.

Personally I have needed mixins on a recent project and have wound up
pushing lots of members up the hierarchy, into base classes, when I would
prefer not to, just to avoid the pain of delegation.

Let me see if I can explain the motivation behind suggestion, "prefer
aggregation over inheritance". If you only use single inheritance, you are
limited by the type hierarchy. Additionally, multiple inheritance has
problems in some languages.

It has problems in theory, not just in some implementations. If you
need to produce the situation described above, use aggregation and
write a simple one line property to return the aggregated class. One
extra line of code to eliminate a wide class of theoretical problems
is pretty darn good.
 
P

Paul Werkowitz

Hello,
Personally, I'd question any design that is encouraging you to
subclass every .NET WinForms Control.
.....

This eliminates the duplication, but it still is requiring you to
subclass every .NET control. I'd consider other design alternatives
that wouldn't require you to do this.

And, which design alternatives could that be? And why are they "better"?


Note: The task is to make all the controls I need in my apps obey certain
protocols. E.G., the container (usualy a form or user control) needs
notification, when the contents of a control have changed (e.g. to enable
save-button, and more).

The protocol is complex: it also connects the controls to business
object(s), maintains error state(s) and information, provides context
sensitive help, and much more.

Now - your preferred solution is?

Greetz
Paule
 
P

Paul Werkowitz

Am Wed, 18 Jul 2007 08:52:41 -0700 schrieb Peter Duniho:
I prefer to use the term "composition". But whatever. Whether you call
it "delegation" or "composition", it works fine.


Then you do so incorrectly.


If you think "the same ambiguity problems can arise", then you don't
understand which ambiguity problems I'm talking about.
I am specifically speaking about the problems that arise when a single
class implicitly inherits the same implementation from the same base class
multiple times.

The C++ term you mean here is probably "virtual base classes".

Unfortunately, virtual bases are inavoidable when dealing with MI, and I
admit that this is not easy to handle. Indeed, it is one of the two most
difficult language features in C++.

But consider the following:

- If the MI is in a class hierarchy of a library, the user does not see it
at all. I wonder whether users of IOStream are aware that they are using
classes with MI.

- The developer of such classes, though, must be able to handle the
complexity. Note that he is not required to use MI - if you can't handle
it, leave it alone! That's what most programmers do, and that's perfectly
OK.

So, the existence of MI in C++ does not impose *any* negative effect upon
those, that do not want to or cannot use it. The situation in C# although
is different: The missing of MI imposes the need for ugly workarounds for
all those, that know how to handle MI correctly. IMHO, that is not good.

In any case, I do not intend to rehash to ridiculous thread that already
occurred in the C# newsgroup about MI. If you think that the lack of MI
in .NET and/or C# is a fundamental flaw, then don't use .NET and/or C#.

Thats not the point. Of course we all use .NET and C# to great benefit. It
should be allowed to question some decisions of the language creators (and,
BTW, most of them are half my age).

Simple as that. If you don't believe it's a fundamental flaw, then get
over it and quit wasting time complaining about the lack of it. There are
workarounds that work fine for people who can get over their love affair
with MI.

I'd love to learn about such a workaround. Note: I want code inheritance,
not interface inheritance. I know that I can implement multiple interfaces
in C#.
The basic behaviors that MI allow still exist in .NET. They just require
writing a little more code, while at the same time avoiding some of the
pitfalls that true MI creates.

yes, then please tell us how to get code inheritance in .NET.

Greetz
Paule
 
R

Richard

[Please do not mail me a copy of your followup]

Paul Werkowitz <[email protected]> spake the secret code
Now - your preferred solution is?

As I already said -- one that doesn't require me to subclass every
WinForm control.

In fact, these days I prefer to move all application logic out of the
form entirely and put it in a separate class. This can be the
Model/View/Controller pattern or it can be the Mediator pattern.
Either, way I don't want to make elaborate protocols on concrete
controls. I separate out all the control interactions into another
class that deals with an interface and unit test the interaction
separately from concrete controls or dialogs.

See
<http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf>
 
B

Ben Voigt [C++ MVP]

Richard said:
[Please do not mail me a copy of your followup]

"Chris Mullins [MVP]" <[email protected]> spake the secret code
In all honesty, I've used [multiple inheritance] quite a bit,
and people I've worked with (many,
very hardcore OO purests) have also used it quite a bit. Does this mean
people may have overused it? Possibly. But this happens with every
technology.

So how do you feel about "Design Patterns" saying you should prefer
aggregation over inheritance?

I think that's a misquote. Isn't it really "prefer aggregation over
_public_ inheritance"?
 
R

Richard

[Please do not mail me a copy of your followup]

"Ben Voigt [C++ MVP]" <[email protected]> spake the secret code
I think that's a misquote. Isn't it really "prefer aggregation over
_public_ inheritance"?

pg. 20:

"That leads us to our second principle of object-oriented design:

Favor object composition over class inheritance."

So, no, they're not weaselling their way out of it by qualifying it as
public inheritance.

They go on to say:

"[...] our experience is that designers overuse inheritance as a
reuse technique, and designs are often made more reusable (and
simpler) by depending more on object composition."
 
M

Mark Wilden

I think that's a misquote. Isn't it really "prefer aggregation over
_public_ inheritance"?

If anything, I think GoF would say "prefer aggregation over private
inheritance."

///ark
 
P

Paul Werkowitz

Am Mon, 23 Jul 2007 08:38:36 -0700 schrieb Richard:
[Please do not mail me a copy of your followup]

Paul Werkowitz <[email protected]> spake the secret code
Now - your preferred solution is?

As I already said -- one that doesn't require me to subclass every
WinForm control.

In fact, these days I prefer to move all application logic out of the
form entirely and put it in a separate class. This can be the
Model/View/Controller pattern or it can be the Mediator pattern.
Either, way I don't want to make elaborate protocols on concrete
controls. I separate out all the control interactions into another
class that deals with an interface and unit test the interaction
separately from concrete controls or dialogs.
This does not help much. You move the logic from the concrete control
classes to other, special classes - you have to write the code for the
logic somewhere. PLUS: You now have another protocol.... between the
control classes and your new classes .... You have to write code to
implement this.

Your solution does not help with the problem of code duplication due to the
lack of MI in C#. It does help when you need to completely separate GUI and
*any* logic. I doubt whether this is useful. E.G. , I have a derived
textbox that accepts only integers. To me, this is a valid candidate for a
derivation.

yes.

Greetz
Paule
 
R

Richard

[Please do not mail me a copy of your followup]

Paul Werkowitz <[email protected]> spake the secret code
Am Mon, 23 Jul 2007 08:38:36 -0700 schrieb Richard:
This does not help much.

I'm not the one sitting in front of your code, either. Generally
problems like this are not solved by reworking one class, because
you've built up a huge system around MI. To refactor it into
something that doesn't use MI is not going to be a small change to one
class.

Are there design alternatives that don't require MI is the question.
I know that they exist, if only due to turing equivalency. Are there
design alternatives that don't require MI and have other desirable
characteristics like low complexity and low code duplication?
Probably, but without assimilating your entire body of source code its
hard to say what they are. And no, that's not an invitation for you
to dump your entire source base on me in this thread. My point is
that there are always design alternatives. Just because I don't show
you a design alternative that you like in this thread based off a tiny
window into your source base is not proof that no such alternative to
MI exists.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top