Switch? Swap? Exchange? Substitution! L is for Liskov Substitution Principle

The L in SOLID is the Liskov Substitution Principle. This one is simple, according to Wikipedia this means:

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

err…what?

To be a little less mathematical – we've got two objects, both of which can be substituted for each other (maybe they implement the same interface, or have the same base class). They each have a method which is required by the interface (or base class). Whichever of the two objects we use, calling that method should only affect what the external caller expects it to affect.

The typical example we get for this (and which is currently on the Wikipedia page) is all about rectangles. So let’s use that:

public  class Rectangle
 {
     private int _width;
     private int _height;
     public virtual void SetHeight(int height)
     {
         _height = height;
     }
     public virtual void SetWidth(int width)
     {
         _width = width;
     }
     public override string ToString()
     {
         return _width + " x " + _height;
     }
 }

This gives us a Rectangle where we can set the height or width and it has a ToString method that writes out the width and height.

Next we create a Square class that uses Rectangle as a base class and overrides SetWidth and SetHeight:

public class Square : Rectangle
 {
     public override void SetWidth(int width)
     {
         SetSize(width);
     }
     public override void SetHeight(int height)
     {
         SetSize(height);
     }
     private void SetSize(int size)
     {
         base.SetHeight(size);
         base.SetWidth(size); 
     }
}

Here we can see that when you set the height or width it calls SetSize which makes both the height and width the same size – which they have to be if it’s going to be a square.

The issue with this is that we should be able to substitute one class with another and still have the same expectations when we call a method. In this case the expectation is that when we call SetWidth we only expect the width to be set. When it starts to do unexpected things like set the height as well then from a programmers point of view it’s going to get confusing.

How do we fix this? Well our initial assertion that a Square should behave like a Rectangle wasn't that great an idea. They've got similar properties but they obey different rules. We shouldn't ever expect them to be interchangeable in this way – that’s the point of the Liskov Substitution Principle!