Re: Deriving - .NET example



Frans Bouma wrote:
Aggregation is in general painful and gains very little, unless
inheritance isn't possible, in which you have to use aggregation, OR in
the case of the lack of multiple implementation inheritance: you then
could try to use aggregation to implement several interfaces at once,
to overcome the lack of multiple implementation inheritance. However I
haven't seen that argument in your motivation.

I snipped all the other stuff, but I'll try to address relevant points here.

As a person who (ab)used inheritance way too much in my life, I am convinced that aggregation is preferable to inheritance where possible. Inheritance is so easy because with three lines of code you get all the functionality of the base class + the public interface of the base class + access to its protected members + the possibility to override some of its implementation.

However, when MyClass is inherited from the base class, then my user directly depend on the interface of the base class. If the interface of the base class changes, users of MyClass will be affected by that change.
We once used some 3rd party grid. It had very cool features, but for some stuff we needed, it was fairly complex to implement it. So we derived class and did it. As the development went on, we used the derived class in many places. However, this introduced strong dependency between our code and the 3rd party class (btw. we only used very small subset of its large interface). Now what happens if we want to change the grid class? There's no easy way to do it. Do we want to do it? No. Might we want it some day? Maybe. However, back than, on the day I inherited from that class (yes it was my doing), I was implicitly stating that we will never do it, or if we want it, that we will pay high price for it.

In addition, in languages such as C# and Java you can have only one base class. So when I derive from one class - that's it. Following is the situation we had some time ago. We introduced the Control derived class which changes its size, based on its content. We called it AutoResizableControl. We also introduced FlowPanel class which mirrored the behavior of .NET 2.0 FlowPanel. At one point we wanted AutoResizableFlowPanel :-) So we did following - make FlowPanel derive from AutoResizable, introduce bool to control whether AutoResizable really autoresizes or not.
This is only a simplification of the problem. There were some other Control derived classes. We ended up with hierarchy with depth of 7 or so. To analyze/debug/maintain such thing was a nightmare.

In static languages (I don't know anything about dynamic ones, so I won't go there) the inheritance is, well, static. That means compiled, imprinted in the binary code, and not changeable in runtime.

On the other hand, aggregation is very dynamic. You can at any time change the aggregated components, and bingo - the behavior changes.
Consider textbook example - you have Employee class and derived variants based on the payment methods, such as HourlyPayedEmployee, SalariedEmployee, CommissionedEmployee etc. which all implement the base abstract method CalculatePay. What happens if at runtime you want to change mode for some employee? You're stuck. Sure there are workarounds to that, but I wouldn't call them elegant.
On the other hand you might extract the calculation part to the separate hierarchy, have base PaymentMethod class with HourlyPaymentMehod, SalariedPaymentMethod etc. The Employee class would contain a reference to its PaymentMethod. The Employee can then at any time in runtime change its PaymentMethod.
This approach uses the combination of aggregation and inheritance (for which I don't think it is bad, I just think it can be easily misused which leads to stronger coupling), and offers more flexibility.


I think it might be good for you to break out the 'aggregation == the
way it has to be done'-mindset which was/is so common among COM/VB
developers (I'm not saying you're a VB developer, the way of thinking
you're expressing is common among them simply because there's no other
way)

I come from a C++ background and had virtually no exposure to VB, and used very little COM. As said, I used inheritance as the reuse many times, and that is precisely why I think inheritance is not preferable. The aggregation offers more flexibility in runtime, and it also shields the users of my class from the changes in the interface/implementation in the classes I use. Because if something changes in the class I use, I have the opportunity to make changes in the implementation of my class so that users of my class don't know that anything has changed.


I also think your example, the Form, is badly chosen for a discussion
about what Inheritance is: a Form has the disadvantage to be a visible
GUI widget/element as well, which are often the end of an inheritance
hierarchy, so there's little room for using the inherited form as a
supertype in another scenario, although it is possible.


Considering the arguments above, I've chosen the Form example because it has specific properties:
1) The designer uses inheritance, even though everything can be achieved by using the instance of the Form class, and introducing separate class which is not derived from anything.

2) The class has very large interface. Wrapping it and offering my own interface to users of my class to my users is the pain in the a**. Further more I would have to do it for every single form I introduce.

3) Since we are talking about Microsoft platform, and Microsoft is the author of the class which is one of the core classes in Windows Forms, it doesn't make sense to remove dependency from it.

Due to 2 and 3 I would say that the argumentation above about preferring aggregation to inheritance doesn't hold, or simply vanishes in comparison. It is very unlikely that Form class will change its interface.
However, I've already experienced one issue when switching to .NET 2.0 where XslTransform class was made obsolete. It was not very pleasant to obtain hundreds of obsolete warnings.

Sasa
.



Relevant Pages

  • Re: Pulling my hair out, I need some help
    ... base class was just that i noticed that a base class saved me more typing ... as using the interface, to the other programmers in my company i made both ... is that the plug-in must meet. ... Inheritance, it is less clear which methods and properties of the ...
    (microsoft.public.dotnet.languages.vb)
  • Re: User Controls (Active X) - Da Process
    ... VB can't do 'real' inheritance. ... VB's 'interface inheritance' is more like interface duplication, ... Even if the class delegates to an internally held base class, ... is duplicated for every level of inheiritance. ...
    (microsoft.public.vb.general.discussion)
  • Re: User Controls (Active X) - Da Process
    ... VB can't do 'real' inheritance. ... For me inheritance includes the implementation as well as the interface. ... code is a duplication of whats in the base class. ... duplicated for every level of inheiritance. ...
    (microsoft.public.vb.general.discussion)
  • Re: difference between inheritance and interface?
    ... By implementing an interface, your object guarantees that the methods laid ... By extending a base class (inheritance), you inherit from the base class ...
    (comp.lang.java.programmer)
  • Re: file as a directory
    ... >>How Do We Write Modifications To An Aggregation ... >>files with delimiters, then emacs need not be changed at all to ... >>aggregation plugin. ... >>Aggregation Is Best Implemented As Inheritance ...
    (Linux-Kernel)