|
From: Sasa on 7 Sep 2006 14:39 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 8 Sep 2006 04:50 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 8 Sep 2006 13:27 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 8 Sep 2006 14:42 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
First
|
Prev
|
Pages: 1 2 Prev: Abstract public member variales? Next: what's the future of Object Oriented Programming |