18

A certain failure of OOP is shown with a class Square inheriting from Rectangle, where logically Square is a specialization of Rectangle and should therefore inherit from it, but everything falls apart when you attempt to change a Square's length or width.

Is there a specific term for describing what is going wrong with that case?

gnat
  • 21,442
  • 29
  • 112
  • 288
Victor
  • 947
  • 7
  • 12
  • 2
    could you please explain what exactly "is going wrong"? I don't understand what you mean – gnat May 24 '13 at 17:24
  • Maybe it makes more sense for Rectangle to inherit from Square. – CWallach May 24 '13 at 17:26
  • 1
    Assuming a rectangle has a virtual method that allows one to set size by passing length and width, setting a different length and width on a square could return a rectangle and setting a same length and width on a rectangle could return a square. Any code that needs to know square explicitly can attempt to cast to a square. I don't see how there is a failure... –  May 24 '13 at 17:31
  • @gnat, if a method had a rectangle, it might assume mutating the width would have no effect on the length. Maybe it doubles with width and expects the area to similarly double. When given a square, that assumption is out the window, provided that the square is correctly implemented. Double the width, the area quadruples. It also begs the question of whether the square needs separate width and length accessors/mutators. – Anthony Pegram May 24 '13 at 18:33
  • 8
    This is not a paradox. This is a case of improper modeling of the problem domain. The inheritance hierarchy is NOT necessarily going to line up with the hierarchy of thing in the problem domain. It's nice when it does, but the trick in a good model is to understand where you need to do things differently than the real world. – Michael Kohne May 24 '13 at 18:38
  • 1
    FWIW: More specifically, the problem is that the reading and writing interfaces don't match up. I.e. you can read a circle as a specialization of an ellipse, but only write an ellipse as a specialization of a circle. – Macke May 24 '13 at 19:07
  • This is not a 'paradox' (not by any dictionary definition of the word). Its not necessarily even a problem. Its only a problem if your application expects specific behavior, possibly incorrectly. A derived 'square' may automatically adjust any changes to its width and height to ensure the object stays a square. If it doesn't do that, then its no different from a 'rectangle' in anything other than name... and the application should be using 'rectangle'. Its all in the behavior thats expected. – GrandmasterB May 24 '13 at 20:29
  • 1
    @GrandmasterB I go by "any person, thing, or situation exhibiting an apparently contradictory nature." The contradiction is that if the square has different properties, we have to say "a Square is not a sort of Rectangle", when it fact we expect Square to be a subtype of Rectangle. Probably no real application would have Rectangle and Square types, it's just an abstraction to illustrate a certain kind of problem that can appear in class-based paradigms. – Victor May 25 '13 at 16:11
  • @Macke that's a good point... maybe it's like set functions giving mutability imply some kind of contravariance? – Victor May 25 '13 at 16:15
  • I think it's more easy to explain with sets: the set of all squares is a subset of all rectangles. And in cases where "any rectangle" will do a square will do. For objects it's different, if a square is inherited from a rectangle. A square will do in all cases that a rectangle will do. But squares are a subset of rectangles......In objects, a child can do all a parent can do....and more. Which goes against the subset that squares are from rectangles. – Pieter B May 08 '14 at 14:32
  • Rectangles and squares as mathematical objects are immutable. Any "stretching" actually creates a new object. Only in that context is a square a rectangle - if they're fully mutable, rectangles have more degrees of freedom, so squares can't be rectangles. To solve it in a program, either make them immutable (like in mathematics), have them be unrelated classes, or put everything in the Rectangle class, and provide a method to test if the dimensions are the same. – Kevin Apr 22 '16 at 15:23

3 Answers3

27

Wikipedia merely refers to it as the Circle-ellipse problem

The circle-ellipse problem in software development (sometimes known as the square-rectangle problem) illustrates a number of pitfalls which can arise when using subtype polymorphism in object modelling. The issues are most commonly encountered when using object-oriented programming.

This is the L in the acronym S.O.L.I.D. which is known as the Liskov substitution principle. This problem arises as a violation of that principle.

The problem concerns which subtyping or inheritance relationship should exist between classes which represent circles and ellipses (or, similarly, squares and rectangles). More generally, the problem illustrates the difficulties which can occur when a base class contains methods which mutate an object in a manner which might invalidate a (stronger) invariant found in a derived class, causing the Liskov substitution principle to be violated...

gnat
  • 21,442
  • 29
  • 112
  • 288
Mark Canlas
  • 3,986
  • 1
  • 29
  • 36
  • 1
    And, reading it, Wikipedia mentions the more academic explanation as "[violation of] the Liskov substitution principle". Thanks :) – Victor May 24 '13 at 17:35
  • 2
    Well, it's only a violation depending on how you look at it. Personally, all circles are ellipses; there is no violation. There begins to be a violation if the methods for ellipse become to restrictive. Then, in that particular scenario, a circle cannot be a subtype of that particular contract of ellipse. – Mark Canlas May 24 '13 at 17:37
  • 6
    @MarkCanlas The problem is unarguably a violation of the Liskov substitution principle. It may not be a violation of other principles, but nobody claimed that. When the problem does not occur because the contracts do not include any invariant that would be broken (though I fail to imagine a useful model where this is true), there may not be a violation of the LSP, but that doesn't mean the *problem*, when it occurs, isn't due to a LSP violation. –  May 24 '13 at 19:02
  • 7
    @Mark Canlas: nope, _constant_ circle is a _constant_ ellipse, mutable circle is not a mutable ellipse. In geometry constantness is assumed, you cannot change an ellipse, you can take another ellipse – maxim1000 May 24 '13 at 19:22
  • @maxim1000: Exactly. After all, the important contribution of the LSP over other definitions of subtyping is the *History Rule*, which allows it to work with mutable objects and not just immutable values like older definitions did. – Jörg W Mittag May 24 '13 at 22:38
  • @JörgWMittag If you'd be so kind; what is the History Rule (or how should I phrase it as a question to ask here)? – Victor May 25 '13 at 16:17
  • 1
    The History Constraint/Rule of the Liskov Substitution Principle says that when a subtype adds new methods, those methods are not allowed to manipulate the state of the object in such a way that it creates a history (i.e. a series of states) that is not allowed in the supertype. E.g. you cannot make a subtype of an immutable mutable, because when only manipulated through methods of the supertype, the state is always the same, whereas when manipulated through the mutator methods of the subtype, the state does change. That's a history that is not allowed by the supertype. – Jörg W Mittag May 26 '13 at 00:27
  • @JörgWMittag: I don't think I'd heard that rule; how would it apply if a derivative of `ImmutableRectangle` offered a mutable `Color` property? My instinct would be that a typical base contract should forbid such a thing, but the basis should be an `equals `contract that promises that if `x.equals(y)` is true, then members of the class itself should not be able to distinguish x from y (the class itself has no way to prevent outside code from testing reference equality). How would the History Constraint deal with that? – supercat Apr 06 '15 at 19:05
8

I would consider it a violation of the Liskov Substitution Principle - the Square subclass specifically violates the invariant that length and width are independent.

Paul Phillips
  • 280
  • 1
  • 5
8

At a more fundamental level than the Liskov Substitution Principle, this is a category error or category mistake

In the context of modeling behaviour a square simply is not a type of rectangle.

When you realize this the problem evaporates since the initial assumption (a square is a type of rectangle) is removed from play.

The issue with this answer is that since school it is drilled into anyone doing geometry that a square is a type of rectangle. But it is very important to understand that this is only true within a very specific context (the classification of geometric shapes based on the properties of their internal angles). In terms of behaviour a square is not a rectangle. To view one set of classification in the wrong context is a category mistake.

Cormac Mulhall
  • 5,032
  • 2
  • 19
  • 19