Liskov substitution principle
The Liskov substitution principle is a particular definition of a subtyping relation, called strong behavioral subtyping, that was initially introduced by Barbara Liskov in a 1987 conference keynote address titled Data abstraction and hierarchy. It is based on the concept of "substitutability" a principle in object-oriented programming stating that an object may be replaced by a sub-object without breaking the program. It is a semantic rather than merely syntactic relation, because it intends to guarantee semantic interoperability of types in a hierarchy, object types in particular. Barbara Liskov and Jeannette Wing described the principle succinctly in a 1994 paper as follows:
Subtype Requirement: Let be a property provable about objects of type. Then should be true for objects of type where is a subtype of.
Symbolically:
That is, if subtypes, what holds for -objects holds for -objects.
In the same paper, Liskov and Wing detailed their notion of behavioral subtyping in an extension of Hoare logic, which bears a certain resemblance to Bertrand Meyer's design by contract in that it considers the interaction of subtyping with preconditions, postconditions and invariants.
Principle
Liskov's notion of a behavioural subtype defines a notion of substitutability for objects; that is, ifS is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program.Behavioural subtyping is a stronger notion than typical subtyping of functions defined in type theory, which relies only on the contravariance of parameter types and covariance of the return type. Behavioural subtyping is undecidable in general: if
q is the property "method for x always terminates", then it is impossible for a program to verify that it holds true for some subtype S of T, even if q does hold for T. Nonetheless, the principle is useful in reasoning about the design of class hierarchies.Liskov substitution principle imposes some standard requirements on signatures that have been adopted in newer object-oriented programming languages :
- Contravariance of method parameter types in the subtype.
- Covariance of method return types in the subtype.
- New exceptions cannot be thrown by the methods in the subtype, except if they are subtypes of exceptions thrown by the methods of the supertype.
- Preconditions cannot be strengthened in the subtype.
- Postconditions cannot be weakened in the subtype.
- Invariants cannot be weakened in the subtype.
- History constraint. Objects are regarded as being modifiable only through their methods. Because subtypes may introduce methods that are not present in the supertype, the introduction of these methods may allow state changes in the subtype that are not permissible in the supertype. The history constraint prohibits this. It was the novel element introduced by Liskov and Wing. A violation of this constraint is, for example, defining a mutable point as a subtype of an immutable point. This is a violation of the history constraint, because in the history of the immutable point, the state is always the same after creation, so it cannot include the history of a mutable point in general. Fields added to the subtype may, however, be safely modified because they are not observable through the supertype methods. Thus, one can define a circle with immutable center and mutable radius as a subtype of an immutable point without violating the history constraint.
Origins
The rules on pre- and postconditions are identical to those introduced by Bertrand Meyer in his 1988 book Object-Oriented Software Construction. Both Meyer, and later Pierre America, who was the first to use the term behavioral subtyping, gave proof-theoretic definitions of some behavioral subtyping notions, but their definitions did not take into account aliasing that may occur in programming languages that support references or pointers. Taking aliasing into account was the major improvement made by Liskov and Wing, and a key ingredient is the history constraint. Under the definitions of Meyer and America, a mutable point would be a behavioral subtype of an immutable point, whereas Liskov substitution principle forbids this.Violation
Liskov substitution principle explains a property, "If for each objecto1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T,". Here is perhaps an example of violation of LSP:
class Rectangle ;
From a programming point of view, the
Square class may be defined as extending the Rectangle class.class Square : public Rectangle ;
However, this violates LSP even though the is-a relationship holds between
Rectangle and Square.Consider the following example, where function
g does not work if a Square is passed in, and so the open-closed principle might be considered to have been violated.void g
Conversely, if one considers that the type of a shape should only be a constraint on the relationship of its dimensions, then the assumption in
g that setHeight will change height, and area, but not width is invalid. This assumption is invalid not only for squares, but even potentially for other rectangles that might be coded to preserve area or aspect ratio when height changes.Specific references
- A keynote address in which Liskov first formulated the principle.
General reference
- This paper surveys various notions of behavioral subtyping, including Liskov and Wing's.
An updated version appeared: The formalization of the principle by its authors.- Contains a gentler introduction to behavioral subtyping in its various forms in chapter 2.
- An article popular in the object-oriented programming community that gives several examples of LSP violations.
- This paper discusses LSP in the mentioned context.