What's wrong with the Square and Rectangle inheritance?-Collection of common programming errors
Consider the abstract base class or interface (whether something is an interface or abstract class is an implementation detail rather irrelevant to the LSP) ReadableRectangle
; it has read-only properties Width
and Height
. It would be possible to derive from that a type ReadableSquare
, which has the same properties but contractually guarantees that Width
and Height
will always be equal.
From ReadableRectangle
, one could define concrete type ImmutableRectangle
(which takes a height and width in its constructor, and guarantees that the Height
and Width
properties will always return the same values), and MutableRectangle
. One could also define concrete type MutableRectangle
, which allows the height and width to be set at any time.
On the “square” side of things, an ImmutableSquare
should be substitutable for both an ImmutableRectangle
and a ReadableSquare
. A MutableSquare
, however, is only substitutable for a ReadableSquare
[which is in turn substitutable for a ReadableRectangle
.] Further, while the behavior of an ImmutableSquare
is substitutable for an ImmutableRectangle
, the value gained by inheriting a concrete ImmutableRectangle
type would be limited. If ImmutableRectangle
were an abstract type or interface, the ImmutableSquare
class would only need to use one field rather than two to hold its dimensions (for a class with two fields, saving one is no big deal, but it’s not hard to imagine classes with a lot more fields, where the savings could be significant). If, however, ImmutableRectangle
is a concrete type, then any derived type would have to have all the fields of its base.
Some types of square are substitutable for the corresponding types of rectangles, but a mutable square is not substitutable for a mutable rectangle.