An introduction to Liskov substitution principle (LSP)

This post is about the Liskov substitution principle (LSP). This is also the third of my posts about SOLID principles, following the posts I wrote about DI and ISP in the past few weeks.

What is Liskov substitution principle (LSP)?

This principle is based on Barbara Liskov’s definition of subtyping, commonly known as the Liskov substitution principle which states the following:

if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program

or in my own words, in programming we cannot always represent our objects with real-life objects and so we need to make sure subtypes respect their parents. Using the illustration below, in order to follow this principle we need to make sure that the subtypes (duck, cuckoo, ostrich) respect the parent class (bird). This means that in our code, we should be able to replace bird with duck, cuckoo or ostrich.

Subtyping

The above illustration shows clearly how in object-oriented programming (OOP) we can reuse some of our classes by making use of inheritance. This also shows very simply how using a base/parent class can be very beneficial and it is a main part of OOP.

So what is the problem you might ask? what is the purpose of the Liskov substitution principle? the purpose of it is to help you avoid some problems when modeling your objects by making you aware of potential problems that aren’t so obvious when using inheritance at the time of development.

The idea is to keep the LSP in mind when developing our classes so a parent class like “bird” can point to any of its child class objects i.e. “duck”, “cuckoo” or “ostrich” during runtime without any issues.

A classic example of LSP violation

One of the most classic examples of LSP violation is the use of a Rectangle class as the parent of a Square class. At first it seems this is the right thing to do as in Mathematics a square is a rectangle. However, in code this is not always true and this is what I meant when I wrote above that you cannot model your objects in code as you would do in the real world.

Below is an example of how in code, something like deriving a class of type Square from a Rectangle class might seem ideal…

public class Rectangle
 {
    public double Height { get; set; }
    public double Width { get; set; }
 }

 public class Square : Rectangle
 {
    public Square CreateSquare(double w)
    {
       var newSquare = new Square
       {
          Height = w, Width = w
       };
       return newSquare;
    }
 }

The example above looks fine, you can call the method CreateSquare by passing a value which is then assigned to both the height and width values of the object, this results in a proper formed square where all sides are equal. The problem arises when you define a rectangle where the height and width have different values, if you then try to substitute that object using a Square object… you will get unexpected results as the Square object expects its height and width properties to have the same value all the time.

However, the Liskov substitution principle says that you should be able to substitute any of the child classes for its base class and the example of the rectangle/square clearly breaks that rule.

The Liskov Susbtitution Principle (LSP) is one of the SOLID principles which can help you during software development to avoid common mistakes that are hard to notice if you are not thinking about them when using inheritance and modeling your classes/objects.

Happy coding!