Catalog / SOLID Principles / Liskov Substitution Principle (LSP)
SOLID

Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types without altering program correctness.

Intent & Objective

If class S is a subtype of class T, then objects of type T may be replaced with objects of type S without breaking client expectations or violating contracts.

πŸ‘₯ Real-World Human Analogies & Social Roles
1 Intuitive Scenarios
Standard AA Batteries Consumer Electronics

"Any brand of rechargeable AA battery can substitute for an alkaline battery in a remote control without breaking device invariants."

The Problem

The infamous Square-Rectangle problem: a Square inheriting from Rectangle overrides setters, meaning setting width also mutates height. Code expecting a rectangle computes an incorrect area or crashes when assumptions fail.

The Solution

Ensure derived classes adhere strictly to the preconditions, postconditions, and invariants of the base class. Favor composition over inheritance if a subclass cannot uphold all parent contracts.

Key Participants & Architectural Roles

Base Contract / Type
Specifies behavioral invariants and guarantees
Proper Subtypes
Honor all preconditions and postconditions without throwing unexpected exceptions

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, LSP enforces that subclasses adhere to behavioral subtyping and contracts. In Functional Programming, LSP is expressed via type systems, algebraic data types, and function signatures: a function expecting `(A) -> B` can safely accept any function with contravariant input and covariant return type.

Advantages

  • βœ“ Guarantees predictable polymorphism across your entire codebase
  • βœ“ Prevents subtle bugs where subclasses break tacit assumptions
  • βœ“ Encourages safe class hierarchies

Trade-offs

  • βœ— Forces developers to rethink naive real-world taxonomies that do not translate into software subtyping

When to Apply

  • β†’ Whenever creating an inheritance hierarchy
  • β†’ When considering overriding base class methods that throw `NotImplementedException`

When to Avoid

  • ! LSP is a fundamental design law; you should never deliberately violate it