# Liskov substitution principle The **Liskov substitution principle** (**LSP**) states that if `S` is a subtype of `T`, then objects of type `T` may be replaced with objects of type `S` without altering the correctness of the program. It was formulated by Barbara Liskov in a 1987 keynote. It is the L in [[solid]]. The principle is about behavioural subtyping, not just structural subtyping. A subclass is allowed to extend a base class syntactically (override methods, add fields), but it must honour the contract of the base class: preconditions cannot be strengthened, postconditions cannot be weakened, and invariants must be preserved. ## A classic violation The textbook example is a `Square` extending `Rectangle`: ```python class Rectangle: def set_width(self, w): self.width = w def set_height(self, h): self.height = h def area(self): return self.width * self.height class Square(Rectangle): def set_width(self, w): self.width = w self.height = w # square constraint: sides must be equal def set_height(self, h): self.width = h self.height = h ``` Code that works correctly with `Rectangle` will break with `Square`: ```python def scale_width(shape, factor): old_height = shape.height shape.set_width(shape.width * factor) assert shape.height == old_height # FAILS for Square ``` The `Rectangle` contract says changing the width does not change the height. `Square` violates this. Substituting a `Square` for a `Rectangle` breaks the function, violating LSP. ## Implication LSP implies that inheritance should model an "is-a" relationship in terms of behaviour, not just structure. A square is geometrically a special case of a rectangle, but it is not a behavioural subtype of a mutable rectangle. The fix is either to make `Rectangle` immutable, or not to use inheritance here at all. The principle guides when to use inheritance versus composition: if you cannot substitute freely, the "is-a" relationship is wrong and composition is likely better.