No Concrete Base Classes

on CirclesAintEllipses, I asked:

Why is it bad to derive one final use class from another? If you have good reasons (or even just authorities), I think they would be worth a page of their own.

I just came across one authority myself:

C++ Gotchas (CppGotchas) by Stephen Dewhurst

(ISBN 0321125185 )

"From the design point of view, public base classes should generally be abstract, because they represent abstract concepts from the problem domain. Just as we don't want or expect to see abstractions wandering around in our physical space... we don't want objects of abstract interfaces wandering around in our program space."

I'm still not convinced. Can anyone provide better justification?

-- AndrewMcGuinness

From a purely pragmatic point of view, I have found it is clearer in tracing code and updating classes if only a single method implementation exists for any class hierarchy. If one starts at the bottom of a class hierarchy and changes the implementation of a method, one would expect the change to propagate up to all users of the class. When a higher-level class has then overridden the function, it leads to problems where the code works in some cases but not in others. As a trivial example, if I change the Show() function on Ellipse to blink, then I would expect the Show() function on an Ellipse derived Circle to blink as well. I would certainly expect that if I call Show on a collection of Ellipses, all would blink. In a two class example, it is easy to manually check for this condition. When there are many derived classes, it becomes very easy to miss those that have overridden base class functionality.

On a more philosophical bent, if one changes the functionality between a base and derived class, one is saying the derived class is different from the base class. The derived class is no longer a specialization of the base class, but a change from the base class. If two "final" classes require different functionality for a method, they should be derived from a base that does not describe the method functionality. In the above example, Ellipse and Circle should be derived from a BaseEllipse? class that does not provide an implementation of Show(). The common features of Ellipse and Circle would be put into BaseEllipse?, while the differences would be placed in Ellipse and Circle.

-- WayneMack

I certainly agree that a derived class shouldn't "break the contract" of the base class by responding to the same messages with different behaviour, but there are cases where you would supply the same behaviour - semantically - with a new implementation.

I'm having difficulty thinking up examples where I'd want to do this (apart from with Exceptions, which could be a special case), so I suppose my real issue is that it would be very easy for a language to either (a) disallow deriving from non-abstract classes, or, alternatively, (b) disallow overriding methods implemented in a base class, but I don't know of any language that does either. Why not, if it's such a good idea?

Probably because language designers are not omniscient. Given that, it is better to err on the side of not being restrictive enough rather than to be overly restrictive.

(I HaveThisPattern: I usually consider that a non-abstract class is final. I also avoid overriding non-abstract methods. -- PhilippeDetournay)

[I break it fairly regurlarly. I will break it for methods that have a default implementation with some exceptions. I will also break it for performance reasons.]

(You should always break a rule if you have a good reason for doing so. A rule is just something that makes you think twice before breaking it.)

I would probably modify the statement from C++ Gotchas to cover abstract methods instead of classes. It would seem appropriate to allow a base class to support both abstract and final methods, but individual methods should be either one or the other.


For what it's worth, I recently did a write up on some of the issues introduced by concrete base classes in Java: http://radio.weblogs.com/0122027/stories/2003/04/21/areConcreteParentClassesACodeSmell.html


See also PrototypeBasedProgramming, which is all about programming without abstract classes. In PrototypeBasedProgramming there are no classes at all, but there can be objects which play some of the roles of concrete classes. -- JasonGrossman


CategoryPolymorphism


EditText of this page (last edited June 12, 2009) or FindPage with title or text search