Liskov Substitution Principle (LSP)
Table of Contents
1 Abstract
Liskov Substitution Principle (LSP) is the L in SOLID Principles of OOD. It clarifies the meaning of inheritance beyond mere syntax. The principle applies to best practices in all OOP languages; certainly to: C++, Java, Scala, and Python. The clarification is crystal clear in the presence of pre- post conditions and class invariant.
[TBD double check use of S (now D) versus T (now B)]
2 Semantics of Inheritance
- If D is a derived type of B, Notation: D <: B, what are the must-have relationships between their methods?
- Regardless of whether our compilers can check these constraints.
2.1 Scenario #1
- A client class C1 is using D. Suppose we replace all occurrences of objects of D with those of B. No other changes are made in C1.
- What behavioral changes can we observe in C1?
2.2 Scenario #2
- (Reverse the roles of D and B.)
- A client class C2 is using B. Suppose we replace all occurrences of objects of B with those of D. No other changes are made in C2.
- What behavioral changes can we observe in C2?
2.3 Observations
- You should construct some examples, run, and observe.
2.4 Statements of Expectations
- "Derived types must be substitutable for base types." All OOP languages permit this. Even when d.m(x, y, z) has radically different behavior from b.m(x, y, z).
- "… derived class objects must be substitutable for the base class objects. That means objects of the derived class must behave in a manner consistent with the promises made in the base class' contract." [from C++ FAQ]
- "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it."
2.5 Define "Behavior"
- Observable state:
- before entering the method (state as described by pre-condition),
- versus leaving the method (post condition)
- Public methods only
- Recall that pre- and post-conditions include the class invariant.
2.6 Origin of Expectations
- The expectations staed above are "best practices" to support software development life cycle, especially maintenance.
- Violating these expectations is bound to cause functional damage to the software.
- E.g., unit tests for the base class would never succeed for the subclass.
3 Proper Inheritance
- Background: ../Assertions
- Consider a public method m(x, y, z) of B and D.
- Preconditions must not be strengthened in a subtype.
- It should be the case that B.m.pre => D.m.pre
- Postconditions must not be weakened in a subtype.
- It should be the case that D.m.post => B.m.post
- Class Invariant B.cinv of the supertype B must be preserved in a
subtype D.
- It should be the case that D.cinv => B.cinv
3.1 More
- OOD Open-Close Principle: Open for extension but Closed for modifications.
- If the above rules are not being held, re-design your inheritance details.
4 Dilemmas?
- Interface substitutability versus Behavior Equivalence
4.1 Circle a subtype of Ellipse?
- Let Ellipse1 have three public observer functions: major, minor, area. Circle1 has the same operations, but minor and major always return the radius.
- Let Ellipse2 have two more public setter functions, major(x), minor(x). Obviously, Circle2 has only major(x).
4.2 Colored Circle
Circle c; ColoredCircle cc; c :=
cc;
Problem?
4.3 Ellipse a subtype of Circle?
4.4 Specialization and Constratints
- We expect a subtype to be a specialization of a base type. The subtype also obeys some extra constraints that the base did not have.
- This works generally – but not always.
4.5 Answers
- Read the answers in Alistair Cockburn (in refs).
5 Liskov's Originals
- "If for each object s of type S there is an object t of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when s is substituted for t then S is a subtype of T." [from Barbara Liskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23, 5, May 1988. Liskov won the Turing Award in 2008.]
- pmateti: The "behavior of P is unchanged" is too strong. Here is a restatement in a later paper:
- Let q(t) be a property (provable) about objects t of type T. Then q(s) should (provably) hold for objects s of type S where S is a subtype of T.
- pmateti: Provability is not the issue.
- pmateti: In the context of our OOPL, treat "type" as a synonym for "class".
6 References
- Liskov, Barbara H., and Jeannette M. Wing. "A behavioral notion of subtyping." ACM Transactions on Programming Languages and Systems (TOPLAS) 16.6 (1994): 1811-1841. http://www.cse.ohio-state.edu/~neelam/courses/788/lwb.pdf. Liskov won the Turing Award in 2008. Highly recommended Reading for CEG4180. Required Reading for CEG 7140.
- http://www.oodesign.com Recommended Visit.
- http://www.parashift.com/c++-faq/ Recommended Visit.
- Alistair Cockburn, http://alistair.cockburn.us/Constructive+deconstruction+of+subtyping A rigorous math logic based discussion of what subtypes are. Highly Recommended Reading.