Search code examples
oopinheritancesolid-principlesliskov-substitution-principle

Difference between the IS-A and Liskov Substitution Principle?


I've just wondered if there is a difference between the IS-A (which is the UML terminology and OOP) and Liskov Substitution Principle (LSP)?

Actually, both are talking about the inheritance. So what is the main difference in practice?


Solution

  • Both terms describe the same "concept" in the end.

    The Liskov substitution principle tells you: an inheritance relation between to classes B (base) and C (child) is sound when each and any usage of some object of type B ... can be replaced with an object of type C.

    This means: B defines an API and a public contract - and C has to uphold these properties, too!

    And IS-A amounts to the same thing: that some object of C is also a B.

    The "difference" is: the LSP gives you exact rules that you can check. Whereas IS-A is more of an "observation" or expression of intent. Like in: you express that you wish that class C IS-A B.

    In other words: when you don't know how to properly use inheritance, IS-A doesn't help you writing correct code. Whereas the LSP clearly tells you that something like:

    class Base { int foo(); }
    class Child extends Base { @Override double foo(); }
    

    is invalid. According to LSP, you can only widen method arguments, and restrict return values.

    int iValue = someBase.foo();
    

    can't be replaced with

    int iValue = someChild.foo();
    

    because the foo() method is widened in its result.

    And a final thought: many people think that C IS-A B is the same as just writing down Child extends Base. Yes. But this only tells the compiler that C extends B. It doesn't mean that the methods you use in C will follow the LSP and thus turn C into a real valid descendant of B.

    C IS-A B requires more than "C extends B". To be truly valid, LSP has to be uphold!