Is deriving square from rectangle a violation of Liskov's Substitution Principle?

liskov-substitution-principle, oop

Solution

I believe the reasoning is something like this:

Let's say you have a method that accepts a rectangle and adjusts its width:

public void SetWidth(Rectangle rect, int width)
{
    rect.Width = width;
}

It should be perfectly reasonable, given what a rectangle is, to assume that this test would pass:

Rectangle rect = new Rectangle(50, 20); // width, height

SetWidth(rect, 100);

Assert.AreEqual(20, rect.Height);

... because changing a rectangle's width does not affect its height.

However, let's say you've derived a new Square class from Rectangle. By definition, a square has height and width always equal. Let's try that test again:

Rectangle rect = new Square(20); // both width and height

SetWidth(rect, 100);

Assert.AreEqual(20, rect.Height);

That test will fail, because setting a square's width to 100 will also change its height.

Thus, Liskov's substitution principle is violated by deriving Square from Rectangle.

The "is-a" rule makes sense in the "real world" (a square is definitely a kind of rectangle), but not always in the world of software design.

Edit

To answer your question, the correct design should probably be that both Rectangle and Square derive from a common "Polygon" or "Shape" class, which does not enforce any rules regarding width or height.

Problem

I am new to design and learning the design principles. It says deriving square from rectangle is a classic example of violation of Liskov's Substitution Principle. If that's the case, what should be the correct design?

Original source