Actual precondition of a subtype is created by combining ( using logical OR
) preconditions of a base type and preconditions of a subtype, which makes the resulting precondition less restrictive
Actual postcondition of a subtype is created by combining ( using logical AND
) postconditions of a base type and postconditions of a subtype, which makes the resulting postcondition more restrictive
The following are examples of strengthening preconditions and weakening postconditions, which as a result violate LSP ( Link ):
Assume your base class works with a member int. Now your subtype requires that int to be positive. This is strengthened pre-conditions, and now any code that worked perfectly fine before with negative ints is broken.
Likewise, assume the same scenario, but the base class used to guarantee that the member would be positive after being called. Then the subtype changes the behavior to allow negative ints. Code that works on the object (and assumes that the post-condition is a positive int) is now broken since the post-condition is not upheld.
a) Why isn't it also considered a violation of LSP when overridden method weakens a precondition, since this method could use parameters that are not acceptable to the contracts of the base type. As such, couldn't we claim that contract of the base type was violated and as a result LSP was also violated?
b) Why isn't it also considered a violation of LSP when overridden method strengthens the postcondition, since clients invoking this method will only receive a subset of possible results of the original method. As such, couldn't we claim that contract of the base type was violated and as a result LSP was also violated?
Example:
Base class postcondition guarantees that the return value of a method would be within range 1-10
, but then the subtype changes the postcondition to only allow return value to be within the range 2-9
. Now code that works on the object returned from this method ( and assumes that the postcondition is within a range 1-10
) is broken since the postcondition is not upheld.
A very common violation of this principle is the partial implementation of interfaces or base class functionality, leaving unimplemented methods or properties to throw an exception (e.g. NotImplementedException).
If a precondition is violated, the effect of the section of code becomes undefined and thus may or may not carry out its intended work. Security problems can arise due to incorrect preconditions. Often, preconditions are simply included in the documentation of the affected section of code.
The Liskov Substitution Principle in practical software development. The principle defines that objects of a superclass shall be replaceable with objects of its subclasses without breaking the application. That requires the objects of your subclasses to behave in the same way as the objects of your superclass.
A good example here is that of a bird and a penguin; I will call this dove-penguin problem. The below is a Java code snippet showing an example that violates the LSP principle. Here, the Dove can fly because it is a Bird. In this inheritance, much as technically a penguin is a bird, penguins do not fly.
Sorry, but you have a logical error in your considerations.
Base class postcondition guarantees that the return value of a method would be within range 1-10, but then the subtype changes the postcondition to only allow return value to be within the range 2-9.
Since code works within range 1-10 and range 2-9 is actually within range 1-10, strenghtening the postcondition should be never a problem.
Same with weakening the preconditions. Allowing the subtype to accept a greater range is not breaking the base type's behaviour. Since the behaviour is introduced in subtype only and only as a precondition for subtype's methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With