Wednesday, April 27, 2011

Does overriding violate Liskov substitution principle?

Overriding breaks Liskov Substitution Principle (LSP) if you change any behavior defined by a base method. Which means that:

1. The weakest precondition for a child method should be not stronger than for the base method.

2. A postcondition for the child method implies a postcondition for the parent method. Where a postcondition is formed by: a) all side effects caused by a method execution and b) type and value of a returned expression.

From these two requirements you can imply that any new functionality in a child method that does not affect what is expected from a super method does not violate the principle. These conditions allow you to use a subclass instance where a superclass instance is required.

If these rules are not obeyed a class violates LSP. A classic example is when you have the following hierarchy: class Point(x,y), class ColoredPoint(x,y,color) that extends Point(x,y) and overridden method equals(obj) in ColoredPoint that reflects equality by color. Now if one have an instance of Set<Point> he can assume that two points with the same coordinates are equal in this set, which is not the case with the overridden method equals. Actually, there is just no way to extend an instantiable class and add an aspect used in equals/hashCode methods without breaking LSP.

Thus every time you break the principle you implicitly introduce a potential bug that reveals when invariant for a parent class that is expected by a client code is not satisfied. However, in real world often there is no obvious design solution that does not violate LSP, so one can use @ViolatesLSP annotation to warn a client that it is unsafe to use class instances in a polymorphic set or in any other cases that rely on the Liskov substitution principle.