I believe the real reason many people feel classes should be final
/sealed
is that most non-abstract extendable classes are not properly documented.
Let me elaborate. Starting from afar, there is the view among some programmers that inheritance as a tool in OOP is widely overused and abused. We've all read the Liskov substitution principle, though this didn't stop us from violating it hundreds (maybe even thousands) of times.
The thing is programmers love to reuse code. Even when it's not such a good idea. And inheritance is a key tool in this "reabusing" of code. Back to the final/sealed question.
The proper documentation for a final/sealed class is relatively small: you describe what each method does, what are the arguments, the return value, etc. All the usual stuff.
However, when you are properly documenting an extendable class you must include at least the following:
- Dependencies between methods (which method calls which, etc.)
- Dependencies on local variables
- Internal contracts that the extending class should honor
- Call convention for each method (e.g. When you override it, do you call the
super
implementation? Do you call it in the beginning of the method, or in the end? Think constructor vs destructor)
- ...
These are just off the top of my head. And I can provide you with an example of why each of these is important and skipping it will screw up an extending class.
Now, consider how much documentation effort should go into properly documenting each of these things. I believe a class with 7-8 methods (which might be too much in an idealized world, but is too little in the real) might as well have a documentation about 5 pages, text-only. So, instead, we duck out halfway and don't seal the class, so that other people can use it, but don't document it properly either, since it will take a giant amount of time (and, you know, it might never be extended anyway, so why bother?).
If you're designing a class, you might feel the temptation to seal it so that people cannot use it in a way you've not foreseen (and prepared for). On the other hand when you're using someone else's code, sometimes from the public API there is no visible reason for the class to be final, and you might think "Damn, this just cost me 30 minutes in search for a workaround".
I think some of the elements of a solution are:
- First to make sure extending is a good idea when you're a client of the code, and to really favor composition over inheritance.
- Second to read the manual in its entirety (again as a client) to make sure you're not overlooking something that is mentioned.
- Third, when you are writing a piece of code the client will use, write proper documentation for the code (yes, the long way). As a positive example, I can give Apple's iOS docs. They're not sufficient for the user to always properly extend their classes, but they at least include some info on inheritance. Which is more than I can say for most APIs.
- Fourth, actually try to extend your own class, to make sure it works. I am a big supporter of including many samples and tests in APIs, and when you're making a test, you might as well test inheritance chains: they are a part of your contract after all!
- Fifth, in situations when you're in doubt, indicate that the class is not meant to be extended and that doing it is a bad idea (tm). Indicate you should not be held accountable for such unintended use, but still don't seal the class. Obviously, this doesn't cover cases when the class should be 100% sealed.
- Finally, when sealing a class, provide an interface as an intermediate hook, so that the client can "rewrite" his own modified version of the class and work around your 'sealed' class. This way, he can replace the sealed class with his implementation. Now, this should be obvious, since it is loose coupling in its simplest form, but it's still worth a mention.
It is also worth to mention the following "philosophical" question: Is whether a class is sealed
/final
part of the contract for the class, or an implementation detail? Now I don't want to tread there, but an answer to this should also influence your decision whether to seal a class or not.