Reputation: 7478
I am reading about LSP in book 'Agile Principles, Patterns and Practices'. It states that:
"A routine redeclaration [in a derivative] may only replace the original precondition by one equal or weaker, and the original post-condition by one equal or stronger."
The term weaker can be confusing. X is weaker than Y if X does not enforce all the constraints of Y. It does not matter how many new constraints X enforces.
How can we understand it in context of Exceptions?
Upvotes: 2
Views: 297
Reputation: 73376
LSP applies to types. So classes in most OOP languages. There are then three ways to consider your question:
1. The exception considered as type
Exception types like for example std::exception
in C++ that can be derived into more specialized exceptions. In order to facilitate error handling code LSP should be applied.
Exceptions are generally poor in behavior and just transport some additional information about error conditions, so that's not too difficult in general.
2. Exceptions considered as a failed precondition
Exception should correspond to exceptional situations that are not expected in normal circumstances. Raising the exception means therefore that the expected normal conditions are not there.
So the conditions to raise the exception in a derived type should be equal or weaker than in the general type.
Let's take the extreme case. Suppose that no exception is foreseen in the base class for a given routine. You would expect or even specify a nothrow
. Code using it this routine would then consider that it's safe and will not foresee any exception catching. Suppose that you then derive this class into one that throws an exception (i.e. the preconditions are stronger, more restrictive): the code written for the base class would be caught off guards if the exception is raised and the general code for the base class could be broken with the specialized class. So LSP would be broken.
3. Exceptions considered as a special result / post-condition
You could argue that in some cases, the exception is a special post-condition. An alternative to a return value.
I would feel rather uncomfortable with this interpretation (since it's not the understanding of many language designers, see discussion about the nothrow). But I have no further objective arguments to invalidate it.
Since LSP is about contracts, you could make this design decision. In this case, a more specialized class can throw a more specialised exception (so the reasoning would then be on the exception type). But should the derived class really throw at least as much exceptions than the original one ? That sounds counter-intuitve. Goto 2.
Upvotes: 1