.NET Forum / .NET Framework / New Users / July 2007
Multiple base classes in .NET
|
|
Thread rating:  |
Larry Smith - 14 Jul 2007 00:49 GMT I just read a blurb in MSDN under the C++ "ref" keyword which states that:
"Under the CLR object model, only public single inheritance is supported".
Does this mean that no .NET class can ever support multiple inheritance. In C++ for instance I noticed that the compiler flags an error if you use the "ref" keyword on a class with multiple base classes. This supports the above quote. However, under the "CodeClass2.Bases" property (part the VS extensibility model), it states that:
"Bases are super types of CodeElements. For Visual Basic and Visual C# there is always only one element in the collection except when the code type is a CodeInterface".
This is true of course since these languages only support single (class) inheritance. However, it should be true for all .NET classes based on the first quote above. My issue is therefore this. I want to retrieve the base class of an arbitrary class in an arbitrary code file by invoking "CodeClass2.Bases.Item(1)". This works in my testing but will it always work for all languages in theory, assuming the class I'm targetting is always a .NET class of course. Thanks in advance.
Arne Vajhøj - 14 Jul 2007 00:59 GMT > I just read a blurb in MSDN under the C++ "ref" keyword which states that: > > "Under the CLR object model, only public single inheritance is supported". > > Does this mean that no .NET class can ever support multiple inheritance. I belive so.
> This is true of course since these languages only support single (class) > inheritance. However, it should be true for all .NET classes based on the [quoted text clipped - 3 lines] > for all languages in theory, assuming the class I'm targetting is always a > .NET class of course. Thanks in advance. If is is arbitrary code, then I belive that you should be using Type BaseType.
And it is obvious that it will only return one type.
Arne
Larry Smith - 14 Jul 2007 01:19 GMT >> I just read a blurb in MSDN under the C++ "ref" keyword which states >> that: [quoted text clipped - 16 lines] > If is is arbitrary code, then I belive that you should be using > Type BaseType. Thanks for the tip. It might prove useful later but for the moment I might not be able to retrieve the "Type" (since my app processes raw source files before they may have even been compiled yet).
Jesse Houwing - 14 Jul 2007 01:04 GMT * Larry Smith wrote, On 14-7-2007 1:49:
> I just read a blurb in MSDN under the C++ "ref" keyword which states that: > [quoted text clipped - 17 lines] > for all languages in theory, assuming the class I'm targetting is always a > .NET class of course. Thanks in advance. The Visual Studio Extensibility model also supports non-CLR languages (native C++ for example), so it has support for multiple inheritance.
The .NET types do not support multiple inheritance as you've already found out. I've read a couple of rumors that multiple inheritance will probably find its way back into the CLR in a future version...
Jesse
Larry Smith - 14 Jul 2007 01:36 GMT > The Visual Studio Extensibility model also supports non-CLR languages > (native C++ for example), so it has support for multiple inheritance. > > The .NET types do not support multiple inheritance as you've already found > out. I've read a couple of rumors that multiple inheritance will probably > find its way back into the CLR in a future version... Thanks for the clarification (appreciated). As for the rumour, I'm not sure how they'll tackle that given that there already seem to be some built-in assumptions based on single-inheritance. They could change this of course but it might cause a lot of problems. Anyway, thanks again.
Mark Rae [MVP] - 14 Jul 2007 02:05 GMT > Thanks for the clarification (appreciated). As for the rumour, I'm not > sure how they'll tackle that given that there already seem to be some > built-in assumptions based on single-inheritance. They could change this > of course but it might cause a lot of problems. Anyway, thanks again. I'd be surprised if we ever see multiple inheritance in C#...
http://blogs.msdn.com/csharpfaq/archive/2004/03/07/85562.aspx http://www.google.co.uk/search?hl=en&rlz=1T4GGIH_en-GBGB220GB220&q=%22c%23%22+mu ltiple+inheritance&meta=
 Signature Mark Rae ASP.NET MVP http://www.markrae.net
Larry Smith - 14 Jul 2007 15:42 GMT > I'd be surprised if we ever see multiple inheritance in C#... > > http://blogs.msdn.com/csharpfaq/archive/2004/03/07/85562.aspx > http://www.google.co.uk/search?hl=en&rlz=1T4GGIH_en-GBGB220GB220&q=%22c%23%22+mu ltiple+inheritance&meta= I'd be surpised as well. It's not likely to take off given that it's already established as single inheritance. Moreover, it's rarely even used in the C++ world. From my own (long) experience in that arena, it makes sense conceptually but in practice it's mechanically very difficult to work with. I doubt significant improvements can be made on this front.
Mark Rae [MVP] - 14 Jul 2007 16:37 GMT > I'd be surpised as well. It's not likely to take off given that it's > already established as single inheritance. Moreover, it's rarely even used > in the C++ world. From my own (long) experience in that arena, it makes > sense conceptually but in practice it's mechanically very difficult to > work with. I doubt significant improvements can be made on this front. Indeed. I've been using C# since the latter half of 2002 and have never had any need for multiple inheritance...
 Signature Mark Rae ASP.NET MVP http://www.markrae.net
Paul Werkowitz - 18 Jul 2007 09:34 GMT Am Sat, 14 Jul 2007 16:37:06 +0100 schrieb Mark Rae [MVP]:
> Indeed. I've been using C# since the latter half of 2002 and have never had > any need for multiple inheritance... Hello, how then can you advise me to implement the following:
I have derivations from the standard WinForm Controls that implement certain protocols for loading, storing, verification etc. Code example:
//----------------------------------------------------------------- // boBindName // [ Bindable (true) , Category ("QFC") , Description ("Feld/Property, an das gebunden werden soll") ] public string boBindName { get { return mBoBindName; } set { mBoBindName = value; } }
I have many of those.
At the moment, I need to have the exact same code in all of my derived controls. Any change in that code must be manually repeated for all controls - a perfect situation for implementation inheritance with the help of MI.
Paule
Richard - 18 Jul 2007 12:22 GMT [Please do not mail me a copy of your followup]
Paul Werkowitz <newsgroups@primaprogramm.de> spake the secret code <1fd4e049y61vc$.i7k81e3krf13$.dlg@40tude.net> thusly:
>Am Sat, 14 Jul 2007 16:37:06 +0100 schrieb Mark Rae [MVP]: > [quoted text clipped - 26 lines] >controls - a perfect situation for implementation inheritance with the help >of MI. Personally, I'd question any design that is encouraging you to subclass every .NET WinForms Control.
MI is only one way to aggregate behaviors, not the only way. In .NET you can implement multiple interfaces to aggregate multiple behaviors into a single class. In .NET 2 you also have generics, so you can do template type tricks:
class BindableControl<T> : T { [Bindable(true)] [Category("QFC")] [Description("...")] public string boBindName { get { return mBoBindName; } set { mBoBindName = value; } } private string mBoBindName; }
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.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Ben Voigt [C++ MVP] - 19 Jul 2007 13:43 GMT > MI is only one way to aggregate behaviors, not the only way. In .NET > you can implement multiple interfaces to aggregate multiple behaviors > into a single class. In .NET 2 you also have generics, so you can do > template type tricks: Sorry, but generics aren't templates, and you can't "do template type tricks".
> class BindableControl<T> : T For instance, that line won't work with generics.
> { > [Bindable(true)] [quoted text clipped - 9 lines] > > This eliminates the duplication, but it still is requiring you to Except it doesn't work.
Richard - 19 Jul 2007 15:09 GMT [Please do not mail me a copy of your followup]
"Ben Voigt [C++ MVP]" <rbv@nospam.nospam> spake the secret code <uD$NxKgyHHA.4004@TK2MSFTNGP05.phx.gbl> thusly:
>> MI is only one way to aggregate behaviors, not the only way. In .NET >> you can implement multiple interfaces to aggregate multiple behaviors [quoted text clipped - 7 lines] > >For instance, that line won't work with generics. Interesting! OK, I didn't know that.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Paul Werkowitz - 23 Jul 2007 13:04 GMT 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
Richard - 23 Jul 2007 16:38 GMT [Please do not mail me a copy of your followup]
Paul Werkowitz <newsgroups@primaprogramm.de> spake the secret code <18luzzej747id.y4zo43yv40mj$.dlg@40tude.net> thusly:
>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>
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Paul Werkowitz - 24 Jul 2007 09:34 GMT Am Mon, 23 Jul 2007 08:38:36 -0700 schrieb Richard:
> [Please do not mail me a copy of your followup] > [quoted text clipped - 13 lines] > 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.
> See > <http://www.objectmentor.com/resources/articles/TheHumbleDialogBox.pdf> yes.
Greetz Paule
Richard - 24 Jul 2007 14:43 GMT [Please do not mail me a copy of your followup]
Paul Werkowitz <newsgroups@primaprogramm.de> spake the secret code <1dcqihpdjh9yz$.11xctw79vbdqo$.dlg@40tude.net> thusly:
>Am Mon, 23 Jul 2007 08:38:36 -0700 schrieb Richard: > [quoted text clipped - 5 lines] >> As I already said -- one that doesn't require me to subclass every >> WinForm control.
>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.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Chris Mullins [MVP] - 18 Jul 2007 20:12 GMT > "Larry Smith" <no_spam@_nospam.com> wrote in message [Multiple Inheritence]
>> Moreover, it's rarely even used in the C++ world. 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's very frequently used, and is a very powerfull tool to have access to.
>> From my own (long) experience in that arena, it makes sense conceptually >> but in practice it's mechanically very difficult to work with. I doubt >> significant improvements can be made on this front. My experience is otherwise. I've used it alot, loved it, had great success with it, and really miss it.
> Indeed. I've been using C# since the latter half of 2002 and have never > had any need for multiple inheritance... I've been using the C# since 2001 (neh! heheh. ) and have had many, many cases where multiple inheritence would have been the correct answer. Without MI, I've been stuck jumping through crazy Interface hoops, duplicating all sorts of implementation logic, and generally been forced to take a very powerfull tool out of my bag of tricks.
I know there are no changes planned on this front, and as a result, I'm beating a dead horse, but I find it quite frustrating. I continually hear people say, "I don't use it, have never used it, and will never use it - therefore it's not needed.".
 Signature Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP http://www.coversant.com/blogs/cmullins
Daniel Marohn - 18 Jul 2007 20:34 GMT > My experience is otherwise. I've used it alot, loved it, had great success > with it, and really miss it. I agree (cannot say how much!)
Larry Smith - 19 Jul 2007 01:21 GMT >>> Moreover, it's rarely even used in the C++ world. > > That's just... not right. Actually it is. I've worked for many different companies both large and small and almost nobody uses it. I find it very hard to believe this isn't the norm.
> 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). Actually it's not full of MI. There's precious little of it in fact. The streams library is really all that there is and its MI model is very simple. If something else exists that uses MI then it escapes me right now as I've been immersed in C# for the last 18 months now (after many years in C/C++). There's nevertheless a big difference between using the STL classes and applying MI in your own code. You normally don't get your hands dirty with it at this level. In fact, from a programmer's perspective it really functions as SI for all intents and purposes. That is, you normally don't deal with the complicatd issues that can make MI difficult to deal with.
> It's very frequently used, and is a very powerfull tool to have access to. I didn't say it wasn't powerful. The mechanics get progressively more difficult to work with however as class hiearchies become non-trivial.
>>> From my own (long) experience in that arena, it makes sense conceptually >>> but in practice it's mechanically very difficult to work with. I doubt >>> significant improvements can be made on this front. > > My experience is otherwise. I've used it alot, loved it, had great success > with it, and really miss it. You must have precious little experience dealing with large class hierarchies then.. 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.
>> Indeed. I've been using C# since the latter half of 2002 and have never >> had any need for multiple inheritance... [quoted text clipped - 9 lines] > people say, "I don't use it, have never used it, and will never use it - > therefore it's not needed.". The lack of MI has caused problems for me as well on occasion. You don't need to duplicate interface logic however but that's another story. In fact. I firmly believe that MI is conceptually superior to C# interfaces since it's a more natural model of objects in the real world. It's mechanically difficult (even challenging) to work with however once you start encountering the problems in my previous point. This is my only real beef with it.
Richard - 19 Jul 2007 02:51 GMT [Please do not mail me a copy of your followup]
"Larry Smith" <no_spam@_nospam.com> spake the secret code <uQGcOrZyHHA.484@TK2MSFTNGP06.phx.gbl> thusly:
>Actually it's not full of MI. There's precious little of it in fact. The >streams library is really all that there is and its MI model is very simple. One library I've seen that uses MI all over the place is ATL, but in that case the MI is used to aggregate various bits of COM behavior.
>You must have precious little experience dealing with large class >hierarchies then.. When you factor in issues like virtual base classes, the [quoted text clipped - 3 lines] >then it becomes a major deterrent very quickly unless your class hierarchies >remain trivial. 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.)
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Larry Smith - 19 Jul 2007 03:10 GMT > "Larry Smith" <no_spam@_nospam.com> spake the secret code > <uQGcOrZyHHA.484@TK2MSFTNGP06.phx.gbl> thusly: [quoted text clipped - 21 lines] > my recollection is that I don't recall any virtual function business > going on when I last studied the ATL Internals book.) I'm very familiar with this book having read it in nauseating detail once upon a time (it's really the bible of ATL). ATL is brutally difficult however. It took me a long time to master it and I have many years of C++ experience. For the less experienced it's downright dangerous. Hardly a good example of MI nor many other techniques (for C++ experts only).
Richard - 19 Jul 2007 04:04 GMT [Please do not mail me a copy of your followup]
"Larry Smith" <no_spam@_nospam.com> spake the secret code <e9pbsnayHHA.5964@TK2MSFTNGP04.phx.gbl> thusly:
>[...] Hardly a good >example of MI nor many other techniques (for C++ experts only). Its just the only library I can think of that uses multiple inheritance heavily.
Other than that, I can't think of a typical Windows library that uses multiple inheritance heavily like that.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Ben Voigt [C++ MVP] - 19 Jul 2007 13:47 GMT > 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.
Richard - 19 Jul 2007 15:10 GMT [Please do not mail me a copy of your followup]
"Ben Voigt [C++ MVP]" <rbv@nospam.nospam> spake the secret code <#oGR1MgyHHA.988@TK2MSFTNGP02.phx.gbl> thusly:
>> 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. [quoted text clipped - 5 lines] > >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.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Chris Mullins [MVP] - 19 Jul 2007 19:14 GMT >>>>> Moreover, it's rarely even used in the C++ world. >>> >> That's just... not right.
>> Actually it is. I've worked for many different companies both large and >> small and almost nobody uses it. I find it very hard to believe this >> isn't the norm. 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.
>> It's very frequently used, and is a very powerfull tool to have access >> to. > > 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.
>>>> From my own (long) experience in that arena, it makes sense >>>> conceptually but in practice it's mechanically very difficult to work [quoted text clipped - 5 lines] > 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.
 Signature Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP http://www.coversant.com/blogs/cmullins
Richard - 19 Jul 2007 21:45 GMT [Please do not mail me a copy of your followup]
"Chris Mullins [MVP]" <cmullins@yahoo.com> spake the secret code <ul2hkCjyHHA.1212@TK2MSFTNGP05.phx.gbl> thusly:
>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?
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Chris Mullins [MVP] - 19 Jul 2007 22:28 GMT > "Chris Mullins [MVP]" <cmullins@yahoo.com> spake the secret code >>In all honesty, I've used [multiple inheritance] quite a bit, [quoted text clipped - 5 lines] > 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.
 Signature Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP http://www.coversant.com/blogs/cmullins
Richard - 19 Jul 2007 23:57 GMT [Please do not mail me a copy of your followup]
"Chris Mullins [MVP]" <cmullins@yahoo.com> spake the secret code <u9VeOvkyHHA.3696@TK2MSFTNGP03.phx.gbl> thusly:
>> "Chris Mullins [MVP]" <cmullins@yahoo.com> spake the secret code >>>In all honesty, I've used [multiple inheritance] quite a bit, [quoted text clipped - 8 lines] >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.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Chris Mullins [MVP] - 20 Jul 2007 00:31 GMT > 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!".
 Signature Chris Mullins, MCSD.NET, MCPD:Enterprise, Microsoft C# MVP http://www.coversant.com/blogs/cmullins
Frank Hileman - 20 Jul 2007 20:01 GMT 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
> [Please do not mail me a copy of your followup] > [quoted text clipped - 31 lines] > then the case would seem to be even stronger against multiple > inheritance. Zachary Turner - 22 Jul 2007 16:49 GMT > Hello, > [quoted text clipped - 38 lines] > 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.
Frank Hileman - 24 Jul 2007 15:54 GMT Hello Zachary,
The theoretical problem I am familiar with is resolving the correct member to invoke when a member with the same name is implemented by multiple base classes. I have not seen other problems except optimization. If members with same name are disallowed, what problems are you referring to? Specifically, what are the problems with the Scala approach?
I chose the property grid example because it does not work with aggregation:
- each aggregated class requires the complexity of a new TypeConverter for serialization and property grid issues
- within the property grid, the properties are no longer grouped by the CategoryAttribute, but by the aggregate, as it must now use an expandable TypeConverter
- select multiple same-typed objects in a designer, and try to modify individual aggregate properties independently
- the right-click reset operation resets the entire aggregate, not the individual properties within
- the end user cannot access the properties directly off the instance at run time, instead of instance.X it becomes instance.aggregate.X
- for the aggregate, one has to decide if a read-only property is provided, or a read-write property with value semantics for the aggregate class. A read-only property works fine when the parent does not need to be notified about modifications, but Visual Studio has problems serializing these. A read-write property with value semantics for the aggregate class requires operator==, etc.
The scala example illustrates some of the power of mixins over single inheritance. Inheritance has advantages over aggregation, otherwise we have no need for even single inheritance.
Regards, Frank Hileman
check out VG.net: http://www.vgdotnet.com Animated vector graphics system Integrated Visual Studio graphics editor
> 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. Ben Voigt [C++ MVP] - 23 Jul 2007 23:15 GMT > [Please do not mail me a copy of your followup] > [quoted text clipped - 9 lines] > 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"?
Richard - 24 Jul 2007 00:07 GMT [Please do not mail me a copy of your followup]
"Ben Voigt [C++ MVP]" <rbv@nospam.nospam> spake the secret code <OU4KUcXzHHA.3908@TK2MSFTNGP05.phx.gbl> thusly:
>> 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"? 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."
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Frank Hileman - 24 Jul 2007 16:13 GMT Hello,
I agree with the quote "designers overuse inheritance as a reuse technique." One could qualify that by saying "inexperienced designers."
We should not conclude that aggregation is preferable to inheritance in all contexts. Such a conclusion favors a "principle" (favor composition) over the motivation behind the principle (inheritance abuse).
Not all use of inheritance is abuse. Mixins are no more susceptible to abuse that other code reuse techniques. Ask people who work in languages with good mixin support if mixins cause more problems than aggregation.
The Gof book is not a bible. It represents a set of opinions at a particular point in history. At that point in time, static class diagrams (uml) were becoming popular. People often assumed they needed to create the class diagram up front, before implementing any of the leaves in the class hierarchy.
Regards, Frank Hileman
check out VG.net: http://www.vgdotnet.com Animated vector graphics system Integrated Visual Studio graphics editor
> "That leads us to our second principle of object-oriented design: > [quoted text clipped - 8 lines] > reuse technique, and designs are often made more reusable (and > simpler) by depending more on object composition." Richard - 24 Jul 2007 16:43 GMT [Please do not mail me a copy of your followup]
"Frank Hileman" <frankhil@no.spamming.prodigesoftware.com> spake the secret code <#MTYrUgzHHA.464@TK2MSFTNGP02.phx.gbl> thusly:
>I agree with the quote "designers overuse inheritance as a reuse >technique." One could qualify that by saying "inexperienced designers." I don't know that this qualification is of much use since everyone starts out as an inexperienced designer. The problem I have seen is that people build up bad habits while inexperienced and then after having used these bad habits for a long time, they call themselves experienced, yet they are still a poor designer.
>We should not conclude that aggregation is preferable to inheritance in all >contexts. That's why its a *preference* and not an outright ban on inheritance.
>The Gof book is not a bible. [...] There's no reason to get insulting by bringing religion into it.
 Signature "The Direct3D Graphics Pipeline" -- DirectX 9 draft available for download <http://www.xmission.com/~legalize/book/download/index.html>
Legalize Adulthood! <http://blogs.xmission.com/legalize/>
Frank Hileman - 26 Jul 2007 15:42 GMT Hi Richard,
Sorry, I meant bible in the slang sense. GoF should not be considered a source of absolute wisdom.
Frank
>>The Gof book is not a bible. [...] > > There's no reason to get insulting by bringing religion into it. Mark Wilden - 24 Jul 2007 01:44 GMT > 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
Ben Voigt [C++ MVP] - 24 Jul 2007 15:01 GMT >> 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." Well, I've always heard that _public_ inheritance must be restricted to cases of is-a. But surely there are cases when protected inheritance is appropriate but public is not. For instance, if you are exposing a readonly collection to your users, it may be helpful to inherit a full featured collection privately, but make only the get accessors visible. Sure, you could use aggregation/forwarding, but here the object is-a readonly collection and also is-a writable collection, depending on the user. That to me just sounds like protected inheritance. Of course, you expose all the mutation functionality to your creator/owner by returning a pair of pointers from a factory method, one cast to the mutable base class and one not.
Sadly, none of this is possible in .NET.
Larry Smith - 24 Jul 2007 17:03 GMT > Well, I've always heard that _public_ inheritance must be restricted to > cases of is-a. But surely there are cases when protected inheritance is > appropriate but public is not. For instance, if you are exposing a > readonly collection to your users, it may be helpful to inherit a full > featured collection privately, but make only the get accessors visible.
> Sure, you could use aggregation/forwarding, but here the object is-a > readonly collection and also is-a writable collection, depending on the [quoted text clipped - 4 lines] > > Sadly, none of this is possible in .NET. I don't think a language should restrict a user from doing this type of thing but I personally find it extremely ugly. IMO (and it is a religious issue) an interface is something that the "public" deals with and they shoulsn't see anything else. If I use a vending machine to "download" a soft drink, I want to see the interface only - coin slot, selection buttons, change drop, etc. I don't want to see a second interface jutting out that has meaning to the manufacuter only (even if I can't use it). It's unsightly and confusing. The whole thing should be hidden which is not the case with protected or private inheritance. Your own collection example is very ugly in practice for instance (IMHO). This is because inheritance of this type isn't normally done to extend a base class' behaviour by adding extra functionality or even overriding existing behaviour. It's normally done to support a new and specifc implementation meaning your new class requires its own independent interface. A generic collection class for instance (say a "vector" that actually supported derivation) will have many different functions which become off-limits the moment I create a specific collection of type T. My new collection is designed to handle T only which usually involves very specific behaviour. It's not a "vector" from the user's standpoint and shouldn't be seen that way. It's a collection of T and that's how you want your users to see it (not as a "vector" even if it's protected/private - it still violates the "is a" relationship from their perspective). I also may not want them invoking the base class' "erase" function, "capacity" function, "reserve" function, etc. I can inherit from "vector" using "protected" or "private" and only expose what I want but users can still see it's a "vector" which is an implementation detail they shouldn't know about (especially since its functionality is off-limits). If I add my own "erase" function for instance (maybe even calling it "delete") then they'll now see two "erase" functions even if only one is accessible. The entire situation is completely unnatural and confusing notwithstanding the inconvenenience of aggregation since it requires new wrapper functions you get for free using inheritance (although even with inheritance you may need to replace a non-virtual base class function which leads to hiding issues and/or dual functions in the derived class - this can result in confusion and difficuties understanding the class even for those maintaining it). Nevertheless, I readily acknowledge that aggregation is a maintenance problem since you can wind up with many wrappers which often do little more than delegate to others (resulting in code bloat, maintenance problems, etc.).
Ben Voigt [C++ MVP] - 24 Jul 2007 18:50 GMT >> Well, I've always heard that _public_ inheritance must be restricted to >> cases of is-a. But surely there are cases when protected inheritance is [quoted text clipped - 21 lines] > not the case with protected or private inheritance. Your own collection > example is very ugly You were completely right... up until here. Non-public inheritance is hidden from the user. Only members can cast to a private/protected base class.
> in practice for instance (IMHO). This is because inheritance of this type > isn't normally done to extend a base class' behaviour by adding extra [quoted text clipped - 8 lines] > and that's how you want your users to see it (not as a "vector" even if > it's That's how they would see it -- via the public interfaces it implements.
> protected/private - it still violates the "is a" relationship from their > perspective). I also may not want them invoking the base class' "erase" > function, "capacity" function, "reserve" function, etc. I can inherit from > "vector" using "protected" or "private" and only expose what I want but > users can still see it's a "vector" which is an implementation detail they How? Protected/private base classes are implementation details and as such are hidden from the user.
> shouldn't know about (especially since its functionality is off-limits). > If I add my own "erase" function for instance (maybe even calling it > "delete") then they'll now see two "erase" functions even if only one is > accessible. Functions in derived classes with the same name but different signatures hide base members, they do not overload. This is why.
> The entire situation is completely unnatural and confusing notwithstanding > the inconvenenience of aggregation since it requires new wrapper functions [quoted text clipped - 3 lines] > confusion and difficuties understanding the class even for those > maintaining The using statement is a lot easier to maintain than a whole barrage of trivial forwarders.
> it). Nevertheless, I readily acknowledge that aggregation is a maintenance > problem since you can wind up with many wrappers which often do little > more than delegate to others (resulting in code bloat, maintenance > problems, etc.). Mark Wilden - 24 Jul 2007 18:22 GMT Ben, you mentioned public, private and protected inheritance. My understanding is that there is no conceivable use for protected inheritance, and, indeed, Stroustrup felt that was a mistake.
///ark
Ben Voigt [C++ MVP] - 24 Jul 2007 18:55 GMT > Ben, you mentioned public, private and protected inheritance. My > understanding is that there is no conceivable use for protected > inheritance, and, indeed, Stroustrup felt that was a mistake. To specify the base class of a template class, where the exact class is chosen by a descendant.
template <typename T> class S : protected T { };
class R : S<std::vector<Q>> { };
Naturally the class choosing the base class should have access to it, but with private inheritance, R couldn't use std::vector<Q>.
Zachary Turner - 19 Jul 2007 16:38 GMT > > "Larry Smith" <no_spam@_nospam.com> wrote in message > [quoted text clipped - 6 lines] > 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.
Peter Duniho - 14 Jul 2007 17:59 GMT (removed microsoft.public.vstudio.extensibility and microsoft.public.dotnet.framework.clr due to lack of relevance and reduction of cross-posting)
> I'd be surpised as well. It's not likely to take off given that it's > already [quoted text clipped - 3 lines] > with. > I doubt significant improvements can be made on this front. IMHO, C# already does make an improvement over multiple inheritance vs C++. That is, a class can in fact inherit multiple interfaces. This allows for the same basic behavior as multiple inheritance, while forcing the programmer to be explicit about how the class is arranged (ambiguity in behavior of base classes shared by multiply inherited classes being one of the bigger stumbling blocks for multiple inheritance in C++, IMHO).
Pete
Paul Werkowitz - 18 Jul 2007 09:41 GMT Am Sat, 14 Jul 2007 09:59:39 -0700 schrieb Peter Duniho:
> IMHO, C# already does make an improvement over multiple inheritance vs > C++. That is, a class can in fact inherit multiple interfaces. A class can implement multiple interfaces - roughly the same as in C++ (minor differences ignored). But a class in C# cannot use implementation inheritance, which can be very useful. You have to duplicate the code, use delegation etc.
>This > allows for the same basic behavior as multiple inheritance, while forcing > the programmer to be explicit about how the class is arranged (ambiguity > in behavior of base classes shared by multiply inherited classes being one > of the bigger stumbling blocks for multiple inheritance in C++, IMHO). No, disagree. The same ambiguity problems can arise when you implement multiple interfaces in a C#-class. The solution is the same, though: Compiler gives notice, and you have to manually resolve the amiguity, usually by qualifying the name. No problem.
Paule
Peter Duniho - 18 Jul 2007 16:52 GMT > A class can implement multiple interfaces - roughly the same as in C++ > (minor differences ignored). But a class in C# cannot use implementation > inheritance, which can be very useful. You have to duplicate the code, > use > delegation etc. I prefer to use the term "composition". But whatever. Whether you call it "delegation" or "composition", it works fine.
>> This >> allows for the same basic behavior as multiple inheritance, while [quoted text clipped - 5 lines] > > No, disagree. Then you do so incorrectly.
> The same ambiguity problems can arise when you implement > multiple interfaces in a C#-class. 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. This simply does not happen in .NET, because you can only inherit implementation from any given class once.
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#. 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.
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.
Pete
Ben Voigt [C++ MVP] - 19 Jul 2007 13:51 GMT > 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.)
Paul Werkowitz - 23 Jul 2007 13:33 GMT Am Wed, 18 Jul 2007 08:52:41 -0700 schrieb Peter Duniho:
>> A class can implement multiple interfaces - roughly the same as in C++ >> (minor differences ignored). But a class in C# cannot use implementation [quoted text clipped - 22 lines] > 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
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|