From: Sasa on
Frans Bouma wrote:
>>That's a downside, but I'll discuss it below. Aggregation is
>>advantage because it decouples user of my class from the Form class.
>
>
> that's just saying it does decouple them, but it doesn't explain the
> advantage.

The users of my class do not directly depend on the Form class.

>>Now I might agree that it doesn't have significant practical benefit,
>>because we are assuming that Form class has stable interface, and
>>that existing interface will be supported in the future versions, and
>>that there probably won't be any significant alternative to the Form
>>class in the future (however the last one we don't know for sure).
>
>
> it has a severe downside: you've to replicate the Form's interface in
> your own class, which creates MORE code, and for what?

That is the reason I introduced this topic. If the class had a small
interface, I wouldn't think twice - the inheritance approach would not
seem appropriate. Why inherit when you don't override?

> WHY do you want to make this so overly complicated? I fail to see it.
> Software development isn't getting better by making things complicated.

I'm discussing it hypotetically. I'm simply wondering (not stating, but
just thinking) would it be better if the generated class was not derived
from the Form. Of course I would not choose the approach to code and not
to use designer. That doesn't mean that the designer code is perfect. Is
it so bad to question the quality of the generated code?

>>>So concluding, what you propose isn't that great... ? :)
>>
>>I'm not really proposing it. The idea came to my mind, but I am
>>basically not sure which approach is more in the OO spirit. I am
>>really trying to explore this to gain better feeling on when to use
>>inheritance, and when not.
>
>
> that's simple. Only use inheritance if you want to create a
> specialized type of an existing type. So YOUR form is a specialized
> type of the existing type Form: you add specific code to it.

Which you can achieve with almost the same amount of code by not
deriving from the Form class.

> If you're not doing that, you don't need inheritance.

The question is - if you can do that without inheritance, and without
introducing any duplication when compared to inheritance approach - do
you need inheritance?

>>>The initially generated class which represents YOUR form doesn't use
>>>polymorphism YET, but can do that, if you want to. As you might
>>>know, a
>>
>>Of course it could. But the way I understand polymorphism - its
>>purpose is to vary implementation while keeping the same (base)
>>interface. If I need to override, it is another responsibility. In
>>that case I basically want to introduce new Form which modifies the
>>default behavior of the Form class. However, in my mind, the
>>designer generated code doesn't modifies the behavior of the Form.
>
>
> adding code to a form is also changing behavior: you add behavior, so
> the behavior isn't THE SAME as the superclass: the superclass' behavior
> is a subset of the subclass' behavior IN THAT CASE (i.e. you don't
> override a single method).

I wouldn't say that adding and changing are the same thing. Adding is
simply introducing new methods to the class. Changing is to me limited
to overriding. You override, you implement your own code for already
existing method. Hence - the behavior has been changed.

>
> This thus means that if a method / property of Control doesn't have to
> be virtual, it's not virtual. The OnXXX methods are called by the
> framework for example to get things done. If you derive a class from

Which are the methods that are not called to get things done (other than
methods that are never called)?

> Form for example, you can either bind to the Closing event, or you can
> override OnClosing for example. As it's not that great to have event
> clutter between supertype/subtype code as it's the same object,
> overriding the method is preferable.

Which designer generated code btw. violates ;-)

What is clutter between supertype/subtype code?

> But is your question simply to find a good example of inheritance?
> Because I'm a little bit puzzled why you still want to go through all
> the trouble of doing it 'differently' which only causes way more code
> and less extensibility.

My question is to learn something new about inheritance, or fortify my
old view about it by questioning the design of the generated code.

Now, I would formulate my current view as follows: I'm still thinking
that white box reuse should be made when the derivates change the
implementation (in my dictionary it means override one or more methods).

However, due to the large public interface of the class Form, and due to
the fact that it is unlikely to change, it is justified that the
generated code derives from it, because wrapping and delegating is
painful, and the gain virtually none.

Sasa
From: Frans Bouma on
Sasa wrote:
> Frans Bouma wrote:
> > > That's a downside, but I'll discuss it below. Aggregation is
> > > advantage because it decouples user of my class from the Form
> > > class.
> >
> >
> > that's just saying it does decouple them, but it doesn't explain
> > the advantage.
>
> The users of my class do not directly depend on the Form class.

why on earth is that a concern? The class which wraps a form depends
on form, correct? So the user of THAT class also depends on form.

First define a reason why the user / consumer of your class must not
be exposed to the Form class. If you can't come up with a reason, this
whole discussion is moot.

> That is the reason I introduced this topic. If the class had a small
> interface, I wouldn't think twice - the inheritance approach would
> not seem appropriate. Why inherit when you don't override?

Well, inheritance is used when you EXTEND the supertype. You seem to
ignore that.

> > WHY do you want to make this so overly complicated? I fail to see
> > it. Software development isn't getting better by making things
> > complicated.
>
> I'm discussing it hypotetically. I'm simply wondering (not stating,
> but just thinking) would it be better if the generated class was not
> derived from the Form.

In that light, you can cook up a gazillion questions. YOUR form is a
specialization of FORM: YourForm is-a Form.

That's not too hard to grasp I think?

> > If you're not doing that, you don't need inheritance.
>
> The question is - if you can do that without inheritance, and without
> introducing any duplication when compared to inheritance approach -
> do you need inheritance?

Let me put forward an example:
public class MyForm: Form
{
public MyForm()
{
}
}

there, my form class. When I open it, it will be shown on screen.
Now your approach

public class MyForm
{
private Form _theForm;

public class MyForm()
{
_theForm = new Form();
}
}

This won't show up as a form, I have to write a LOT of code to get
that working.

Now I ask you: you have two ways to achieve goal G: route A and route
B. Route A is simple, flexible, extensible and maintainable. Route B is
complex, time consuming, not maintainable and cumbersome.

Which route would you take? A or B? I guess A. Why are you then
arguing route B is perhaps better?

This isn't MFC/VB/COM, this is a real OO environment.

> > Form for example, you can either bind to the Closing event, or you
> > can override OnClosing for example. As it's not that great to have
> > event clutter between supertype/subtype code as it's the same
> > object, overriding the method is preferable.
>
> Which designer generated code btw. violates ;-)

how? By the initializecomponent method? I already explained that to
you.

> What is clutter between supertype/subtype code?

adding an eventhandler in a subtype to an event of the supertype,
which effectively comes down to calling a virtual/abstract method in
the supertype and overriding it in the subtype, but much less efficient.

> > But is your question simply to find a good example of inheritance?
> > Because I'm a little bit puzzled why you still want to go through
> > all the trouble of doing it 'differently' which only causes way
> > more code and less extensibility.
>
> My question is to learn something new about inheritance, or fortify
> my old view about it by questioning the design of the generated code.

I don't have the feeling you're willing to learn anything. I don't
mind discussing topics, but this discussion is so academic and smells
so much like "I just want to discuss something so I pick a random
position and argue it to death with silly arguments". You haven't
brought forward a single reason why aggregation is better in this case
WITH a definition of 'better'. As long as that's not defined, this
whole discussion is rather a waste of time.

> Now, I would formulate my current view as follows: I'm still thinking
> that white box reuse should be made when the derivates change the
> implementation (in my dictionary it means override one or more
> methods).
>
> However, due to the large public interface of the class Form, and due
> to the fact that it is unlikely to change, it is justified that the
> generated code derives from it, because wrapping and delegating is
> painful, and the gain virtually none.

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 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 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.

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
From: Sasa on
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
From: Sasa on
Couple of specific answers here:

Frans Bouma wrote:
>>>Form for example, you can either bind to the Closing event, or you
>>>can override OnClosing for example. As it's not that great to have
>>>event clutter between supertype/subtype code as it's the same
>>>object, overriding the method is preferable.
>>
>>Which designer generated code btw. violates ;-)
>
>
> how? By the initializecomponent method? I already explained that to
> you.

Via designer you can only subscribe to the event of the base class. You
can't override the OnXXX method which is stated by the MSDN as
preferred. So MS designer really contradicts MS documentation. I think
though, designer is doing this the right way (see below).

>>What is clutter between supertype/subtype code?
>
>
> adding an eventhandler in a subtype to an event of the supertype,
> which effectively comes down to calling a virtual/abstract method in
> the supertype and overriding it in the subtype, but much less efficient.

Those are to me two very different cases. To override means to
reimplement, to change the behavior. To subscribe to an event means to
get some notification and do some custom stuff when it is received.

What happens when you override the OnXXX method? You have to call the
base method, because it fires the event. Why should the method which
fire the event be virtual is almost uncomprehensible to me. One possible
scenario I see is that you want to do something immediately before/after
the event is fired, but this could also be resolved via two more events,
or even better by some AOP like support in the language.

Sasa