## In short Strengthening the preconditions and weakening post conditions is not at all the same. These conditions have a different nature regardless of how you enforce them. In many case, you could weaken preconditions or strengthen pre conditions independently, while both may result failed tests cases when reusing super-type tests for the sub-type. ## More details ### On LSP and contracts LSP is about promises made in a **contract**: * **preconditions** need to be **fulfilled before the an operation is performed**. If you call the operation when they are not met, it doesn't mean that you have to throw exceptions. It just means that the promises of that operation (invariants, post conditions) are no longer guaranteed. * **postconditions** is what must be **guaranteed after the operation is performed**, provided the preconditions were initially met. If they are not fulfilled, there's something wrong in the code. ### Contracts are not about exception (and vice-versa) The pre-/post-conditions do not need to be implemented by the type and its subtype. Adding checks and exceptions (inside the the operations, or outside before/after calling them) is defensive programming. Throwing may be the sign of a failed pre/post-condition. But an exception could as well be a promised behavior of the contract. For example the following contract would make your subtype LSP compliant without changing anything in the code: > *`Task::Close()` ensures that the task is in a closed state if closing is possible or that an exception `TaskCannotBeClosed` is thrown.* In this case, in your `Task` no exception is thrown not because of a different contract but because simpler tasks can alway be closed and hence, no need to throw. And throwing for `ProjectTask` is no longer a strengthening of preconditions. ## Example with independent pre and post conditions. Take the following pseudo-code, which has unrelated pre and post conditions. **Please ignore all the other design and style issues**, it's just to illustrate the case: class Transaction { ... Money sellProduct (Customer c, Product p, Quantity q) { if (c.age()<12) // precondition: Customer is aged 12+ throw CustomerTooYoung; ... // do something if (valueCashedIn < Money(0.00)) // postcondition: amount cashed-in is >=0 throw InternalErrorOnValue; return valueCashedIn ; } ... } You would have an LSP infringement by strengthening the precondition if you would have a TransactionDangerousGoods that has a precondition that customer is 18+. Absolutely no impact on postcondition. You would have an LSP infringement on post-condition, if you would have a Takeback class as subtype of Transaction, if the tackeback would misuse the `sellProduct()` to return the reimbursed amount as negative value.