Liskov Substitution Principle

Click to share! ⬇️

liskov substitution

We’re moving forward with our study of the SOLID design principles, and now we have made it to the L. The L stands for Liskov Substitution Principle or LSP and is named after the creator of the principle, Barbara Liskov. The formal definition is very verbose, so in this tutorial, we will cover the topic as if we are writing the first draft for the book, “The Liskov Substitution Principle For Dummies.” Let’s learn a bit more about this principle now.

You Have The Wrong Abstraction

SOLID is all about abstraction, and mostly about the correct use of interfaces. SOLID is completely intertwined, and at the end of it all, you could almost just say, “Code to an Interface,” and that would be it. Next lesson. Here is a funny one.
liskov substitution principle

If it looks like a Duck, Quacks like a Duck, but needs batteries, – You probably have the Wrong Abstraction.

-the internet

I believe the idea that this is getting to is that, once you start relying on abstractions in your programs, it becomes important that those abstractions are able to be interchanged freely without causing breakage to the program. Stack Overflow has this quote in the most popular answer to the question.

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

-Robert Martin

It turns out this actually comes from Robert Martin, as a paraphrase for Barbara Liskov’s own official definition here:

What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

-Barbara Liskov

In our little world of working with dependency injection and type hinting in PHP and Laravel, this would mean something like this. Given a class A that depends on B, if we pass in a C when we initialize A, everything should still work perfect. Let’s explain this in code. We want to write a program, and the only goal is that it outputs a string that says, “doing something”. Here is our client code, or our program.

$a = new A(new B);
$a->amethod();

// doing something

Perfect. We wrote a program that does what we want it to do. Now, the Liskov Substitution Principle states that we should be able to create a new class that extends B, and when we pass in that derived instance, instead of the original, everything will still work. Another way to say this is that, derived classes must be substitutable for their base classes. With that, lets create a new class C that extends B.

class C extends B {
    public function dosomething()
    {
        return 'doing something';
    }
}

Now, let us substitute the child class for the base class in our client code.

$a = new A(new C);
$a->amethod();

// doing something

Nice. Our program still works perfect, even though we pass in a C (derived) instead of a B (base). Note that we did not even change anything in Class A, it still expects to receive an instance of class B in its constructor. For all intents and purposes, the A object basically still believes that it is calling a method on a B object when in reality it is calling a method on a C object. This is the Liskov Substitution Principle in action. Let us now break the LSP with a new class D that also extends B.

class D extends B {
    public function dosomething()
    {
        return 'doing something ELSE';
    }
}

Now we can call our client code again, and pass in a D instead of a B or C.

$a = new A(new D);
$a->amethod();

// doing something ELSE

Fail. Technically, the program still runs, but we are not meeting the objectives of the program. It is not behaving as intended. Recall that our program is supposed to output “doing something”. When we pass in the base class B, it correctly outputs “doing something”. In fact when we substitute our base class of B for a derived class C, our program still outputs “doing something” so it is working as designed and passes the LSP. Finally, we pass in a D instance, and suddenly our program outputs “doing something ELSE”. We swapped out our base class with a derived class, and the program broke. This is the most basic example of the Liskov Substitution Principle I could think of.

The Liskov Substitution Principle in the Real World

Since I don’t have a PhD in computer science like Barbara and some of the other great minds that came up with the patterns in solid design, I often have to break it down to something so simple that you would never use it in reality. What this does accomplish however is forcing one to think about the concept and process it until it is understood fully enough to come up with an example in very basic terms. This allows us to apply the principle to more real world applications.

Learn More About The Liskov Substitution Principle

Stack Overflow Thread About The Liskov Substitution Principle

The Liskov Substitution Principle According To Robert Martin

Cunningham and Cunningham discuss the Liskov Substitution Principle

Great Youtube Presentation About The Liskov Substitution Principle

Learn About The Power of Abstraction from Barbara herself

The Liskov Substitution Principle Summary

Like most of the ideas presented in solid programming, the Liskov Substitution Principle aims to make programs that are more robust and maintainable over time. Ultimately, the main goal of LSP is that any derived class can be used transparently and with 100% confidence anywhere the original class is used. If you swap out the base class with a derived class and the program fails, you know that it breaks the LSP.

Click to share! ⬇️