CodePark/ questions / SOLID
START PRACTICINGPRACTICE
Backend question · Software design & patterns › SOLID

Explain the Liskov Substitution Principle using the Square/Rectangle example. Why is a square not a safe subtype of rectangle in code?

class Rectangle {
  constructor(protected w: number, protected h: number) {}
  setWidth(w: number) { this.w = w; }
  setHeight(h: number) { this.h = h; }
  area() { return this.w * this.h; }
}
class Square extends Rectangle {
  setWidth(w: number) { this.w = w; this.h = w; }
  setHeight(h: number) { this.w = h; this.h = h; }
}

A square breaks the promise that a rectangle's setWidth makes, so callers get wrong results. LSP (the Liskov Substitution Principle) says that code written for a base type must keep working when you give it any subtype. Subtyping is about behaviour, not just matching method signatures.

A mutable (changeable) Rectangle promises that setWidth changes only the width. A caller may write r.setWidth(5); r.setHeight(4); and expect area() to be 20. With a Square, setting the height also changes the width, so the area is 16.

Square compiles and has the same methods as the class. But it breaks the postcondition of setWidth. A postcondition is what a method promises will be true after it runs. So Square is not substitutable, even though a square is a rectangle in geometry.

The formal rules. A subtype:

  • cannot strengthen preconditions (it cannot demand more from its inputs)
  • cannot weaken postconditions (it cannot promise less about its results)
  • must keep the base type's invariants (the facts that are always true about the object)

Fixes:

  • make the shapes immutable (they cannot change after creation)
  • or have both implement a Shape interface with area(), instead of Square inheriting from Rectangle
  • Subtypes must be usable in place of the base type without breaking callers.
  • Square breaks the postcondition that setWidth leaves the height unchanged.
  • A subtype must not strengthen preconditions or weaken postconditions, and must keep the invariants.
  • Fix it with immutability, or with a common interface instead of inheritance.