|
Prev: Is 'Final' for classes and methods a good feature or somethingthat should be eliminated?
Next: Call for Papers (Extended Deadline): 2007 International Conference on Modeling, Simulation and Visualization Methods (MSV'07), June 25-28, 2007, USA
From: AndyW on 20 Feb 2007 16:52 On Tue, 20 Feb 2007 14:22:13 GMT, Michael Feathers <mfeathers(a)objectmentor.com> wrote: > >Funny thing about *final*. It looks like a great feature. You get to >decide whether a class can have subclasses or whether a method can be >overridden, but now I think it is too easy to abuse. Sure, if you have >control over all of your code, you can make things *final* and remove >*final* when it gets in the way, but if you develop code for someone >else you can easily put them in a situation where it is hard or >impossible to write unit tests for particular areas of code. > >Classic example: > >You have a class A from Vendor X and it has 15 methods. One of your >classes, B, uses it and one of the methods that it uses has some >sideffect you wouldn't like to see happen in a test. You'd like to mock >out that method on A, and you could by subclassing A and overriding the >method, but if Vendor X made A or that method of A final, your options >are limited. > >---- >Michael Feathers >www.objectmentor.com >michaelfeathers.typepad.com >author of: Working Effectively with Legacy Code (Prentice Hall 2005) To be different from probably the other posts that may follow. I would suggest that if something can be derived from further, it isnt an object but a form of abstraction (either a concrete abstraction that can have an instance or a virtual abstraction that cannot be instantiated). If one really thinks about it from a purist perspective. Objects cannot be derived from further although they can be combined with other objects (although many people do not hold this view and it is my own). So, the final keyword really only should be valid if the entity cannot be derived from further anyhow, which other than acting as an indicator to make this clear, really I think serves no real purpose. ---------------- AndyW, Mercenary Software Developer
From: Jerry Coffin on 21 Feb 2007 00:27 In article <puDCh.148$PL.26(a)newsread4.news.pas.earthlink.net>, mfeathers(a)objectmentor.com says... > > Funny thing about *final*. It looks like a great feature. You get to > decide whether a class can have subclasses or whether a method can be > overridden, but now I think it is too easy to abuse. Sure, if you have > control over all of your code, you can make things *final* and remove > *final* when it gets in the way, but if you develop code for someone > else you can easily put them in a situation where it is hard or > impossible to write unit tests for particular areas of code. [ ... ] Java's final strikes me as an example of second-system effect. Especially early on, C++ really could have used final or something very similar. In fact, upon close analysis Scott Meyers once stated (mostly correctly, IMO) that in a C++ hierarchy, classes should divide into two groups, with no overlap: abstract classes that can't be instantiated, and leaf classes from which no further deriviation is allowed. FWIW, he originally wrote about this in the July/August 1994 issue of The C++ Report. Doing a bit of looking, he also posted a bit about it on Usenet around the same time: http://groups.google.com/group/comp.lang.c++/msg/dc1a601560ba8dcf Had it been available in early C++, a final keyword probably would have been quite useful. In fact, I would tend to agree with Scott Meyers that most (perhaps all) concrete classes should have been treated as final. This problem hasn't entirely disappeared from C++, but large hierarchies mostly have, so its utility would now be much more limited (at most). Java eliminated most (if not all) of the reasons final would have been a good thing in C++, then included final anyway. In Java, final is associated with problems far more than solutions. -- Later, Jerry. The universe is a figment of its own imagination.
From: Daniel T. on 21 Feb 2007 07:59 Michael Feathers <mfeathers(a)objectmentor.com> wrote: > Funny thing about *final*. It looks like a great feature. You get to > decide whether a class can have subclasses or whether a method can be > overridden, but now I think it is too easy to abuse. Sure, if you have > control over all of your code, you can make things *final* and remove > *final* when it gets in the way, but if you develop code for someone > else you can easily put them in a situation where it is hard or > impossible to write unit tests for particular areas of code. As far as the "final" keyword I think it should be an automatic designation, not something the programmer decides on. In essence, I agree with Jerry Coffin. If objects can be made from the class, then they should be final by default. Such an idea would make the brittle base class problem go away. > Classic example: > > You have a class A from Vendor X and it has 15 methods. One of your > classes, B, uses it and one of the methods that it uses has some > sideffect you wouldn't like to see happen in a test. You'd like to mock > out that method on A, and you could by subclassing A and overriding the > method, but if Vendor X made A or that method of A final, your options > are limited. I agree with HS Lahman about the example, but that still leaves the question as to what to do in that situation, and the answer is an adaptor. Vendor X apparently did not provide a suitable abstraction ("interface") for class A. So you need to write your class B to use an interface "InterfaceA", one subclass will contain an A object and rout all calls to it, while the other subclass intercepts calls to the problematic methods.
From: Daniel T. on 21 Feb 2007 12:46 Michael Feathers <mfeathers(a)objectmentor.com> wrote: > I'd agree there if popular languages allowed you a way to retrofit > interfaces on classes that are shipped without them. Unless you have > that feature, you're stuck. > > Your comments do make it clear, though, that it isn't final per se > that's the issue. It's final without any form of substitution that's > problematic. I understand the misreading but your comment brings to light a rather glaring oddity to me... The languages (like Objective-C and I think Ruby) that allow one to add new methods to a class are exactly the kinds of languages (dynamic-typed) that don't need such a feature. It would be nice to see a static-typed language that allows one to retrofit an interface onto an already written class without modifying that class. That would solve a lot of problems that people have in static-typed languages IMHO.
From: Dmitry A. Kazakov on 21 Feb 2007 13:08
On Wed, 21 Feb 2007 17:46:12 GMT, Daniel T. wrote: > It would be nice to see a static-typed language that allows one to > retrofit an interface onto an already written class without modifying > that class. Only two things are needed for that: supertyping and multiple inheritance/export. The pattern is very simple: T -> S -> I T is the type. I is the interface (or even a concrete type). S is a new proxy type which is a supertype of T and a subtype of (implements) I. S could be anonymous. Because -> is transitive, so T -> I. Done. > That would solve a lot of problems that people have in > static-typed languages IMHO. Yes! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |