Liskov substitution principle

The Liskov substitution principle (LSP) states that objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. Introduced by Barbara Liskov in 1987, it is the L in SOLID, a family of design principles for object-oriented programming.

LSP is a principle about behavior, not about naming. A subtype must honor the contract of its base type – its preconditions, postconditions, and invariants – so that any code written against the base type continues to work when given a subtype instead. This is what makes polymorphism safe: clients can depend on an abstract type and remain oblivious to which concrete subtype they receive, provided every subtype is a true behavioral substitute.

Violations most often arise when inheritance is used for code reuse rather than to model a genuine "is-a" relationship. A classic example is deriving Square from Rectangle. A square cannot accept arbitrary width and height independently, so it breaks the postconditions of its base type. The subclass compiles, but any code that sets width and height separately and expects them to stick is now wrong. When the "is-a" relationship does not hold at the behavioral level, composition is usually the better answer than inheritance.

Following LSP keeps hierarchies honest. Subclasses that strengthen preconditions, weaken postconditions, or throw exceptions for inputs the base type accepts are all tells that the hierarchy is modeling reuse rather than subtyping. Like the other SOLID letters, LSP is easiest to satisfy when each type has a single, well-defined responsibility, which is the concern of the single responsibility principle, and when extensions are additive rather than modifying, which is the goal of the open-closed principle. It also underpins dependency inversion, which relies on clients depending on abstractions whose concrete implementations are fully substitutable. And it depends on interfaces being narrow enough that every implementer can honor the full contract, which is the concern of the interface segregation principle: a fat interface pressures implementers into stubbing or throwing on methods they cannot support, which is itself a substitution violation.