Liskov Substitution Violations (OOP)

Imagine you have two classes. A parent and a child class. The child inheritance from the parent. Therefore the child should be able to do everything that a parent does and possibly more.

class Duck
    def walk
    end

    def talk
    end
end


class MallardDuck < Duck
    def walk
         raise NotImplementedError, "Mallard Ducks can't walk"
    end

    def talk
        raise NotImplementedError, "Mallard Ducks can't talk"
    end
end

# We got to the park and decide to see some
# ducks go about their business.
# we spot a Mallard duck and we ask it to
# walk and talk

Duck d = Mallard.new()

d.walk
# Error!

d.talk
# Error!

Hang on a second: aren’t all ducks meant to be able to walk and talk? They might surely walk and talk in different ways, but if they don’t walk or talk at all: then are they really ducks? Some people might argue that not walking at all, or rather walking in a NotImplementedError fashion is a particular type of walking - that it’s a particular type of gait. The problem with that is that it comes perilously close to saying that a Mallard Duck is not really a duck at all - especially if ducks are meant to walk and/or talk in some kind of way.

If you see this type of thing, then you are seeing a case of a Liskov Substitution violation. This is a case where a sub-class is not perfectly substitutable for a parent class, because in this particular case, if such a substitution is made, then we get nonsensical results. Ducks are meant to waddle, and quack - in different ways. And if they can’t do that, then surely, they are not ducks?

Written on June 1, 2017