SO[L]ID - Liskov Substitution Principle

Subscribe to receive new articles. No spam. Quality content.

Hi guys, let's continue learning SOLID principles. Today we will talk about Liskov Substitution principle. The principle, that Barbara Liskov defined in 1987 in her conference keynote named "Data abstraction and hierarchy".

Definition says:

if S is a subtype of T, then objects of type T may be replaced with objects of type S

If I had to rephrase definition of Liskov Substitution Prinicple for Ruby programming language, I would define it like this:

If class Man is inherited from class Human, then objects of class Human may be replaced with objects of class Man

It might not be as accurate as original one, because original definition mentions "types" and "subtypes". But we use Duck Typing in Ruby:

if it looks like a duck and quacks like a duck, it's a duck

Let's try to come up with some examples.

First of all we need to define basic class, let's call it Human:

class Human
  def talk
    ''
  end

  def height
    ''
  end
end

Now we can define couple "subtypes":

class HomoHabilis < Human
  def talk
    'Agrrr!'
  end

  def height
    '1.29m'
  end
end

class HomoSapiens < Human
  def talk
    'Hello!'
  end

  def height
    '1.70m'
  end
end

Now we should be able to use these subtypes instead of basic type Human:

habilis = HomoHabilis.new
sapiens = HomoSapiens.new

def introduce_human(human)
  puts "Hi, I'm #{human.height} height and I say #{human.talk}"
end

introduce_human(habilis) # => Hi, I'm 1.29m height and I say Agrrr!
introduce_human(sapiens) # => Hi, I'm 1.70m height and I say Hello!

Just a side note: because we have Duck Typing, we could create class which wouldn't be inherited from basic class Human, but could implement the same interface: height and talk and that would work too. That's where polymorphism kicks in.

So far we used inheritance and that allowed us to substitute objects of parent class with objects of inherited classes. How could we break Liskov Substitution Principle then? Any inherited class would have all methods from basic class, so we should be able to substitute one by another.

To understand that I want to show you description of this principle from Wikipedia:

Liskov substitution principle (LSP) is a particular definition of a subtyping relation, called (strong) behavioral subtyping

I like that part: (strong) behavioral subtyping.

Programming languages with strong typing have less chances to break Liskov substitution principle. Because they strictly define types of method arguments and returning values.

In case of Ruby we are responsible for that. We can easily break Liskov substitution principle by changing returning type and that would make substitution impossible:

class HomoSapiens < Human
  def talk
    'Hello!'
  end

  def height
    { men: '1.70m', women: '1.62' }
  end
end

Now HomoSapiens returns hash instead of string for height. That might break code that expects string from height method call.

Inheritance works when it's a is-a relation type. So HomoSapiens is a Human, that works. But wrong usage of inheritance would break Liskov Substitution Principle as well:

class HomoHabilis < Human
  def talk
    'Agrrr!'
  end

  def height
    '1.29m'
  end

  def social_security_number
    raise NotImplementedError
  end
end

class HomoSapiens < Human
  def talk
    'Hello!'
  end

  def height
    '1.70m'
  end

  def social_security_number
    "AAA-GG-SSSS"
  end
end

In this case we can not substitute HomoSapiens by any object of class Human or its "subtypes" (HomoHabilis) because those don't respond to social_security_number properly, which might break our application. In this case wrong usage of inheritance breaks Liskov Substitution Principle.

It's interesting to see how all SOLID principles are related to each other and to basic ideas of OOP: polymorphism, inheritance, 'is-a' vs 'has-a' types of relations between classes.

I hope that helped to understand the idea of this principle and showed how to keep objects of the same types and subtypes substitutable.

Thanks for reading!

Read more about SOLID Principles in case if you missed it:

Subscribe to receive new articles. No spam. Quality content.

Comments