3

I'm having a really hard time in understanding how pre-conditions and post-conditions must work, without violate the Substitution Principle. So let's assume that we have a class Rectangle and Square—how to relate them? Which one must be the subclass?

So I undertand that the pre-conditions of a Subtype can be weaker, that means that we can take a major 'set' of things in out subclass, on the other hand the post-condition can be stronger so we can return a minor 'set' of things. How can I appply these rules in my example?

I read that the baseclass must 'do' less than the subclass, so I think that Square must be our baseclass and Rectangle the subclass. Thus the pre-condition in Square must be assert that height == width, but what about the post-conditions and the pre-conditions in Rectangle?

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Francesco
  • 521
  • 1
  • 6
  • 14
  • 1
    I would say both `Square` and `Rectangle` are `subclasses` of `Shape` – nafas Oct 27 '15 at 11:07
  • assume that i want to set one of the fist two as subclass of the other – Francesco Oct 27 '15 at 11:09
  • hmm, so every `Square` is a `Rectangle` --> `Rectangle` is a superClass of `Square` – nafas Oct 27 '15 at 11:12
  • 1
    so in that case square must have stronger pre-condition in order to check heigth == width, so it violates the SP principles – Francesco Oct 27 '15 at 11:13
  • yes, condition for rectangle is (it has height and width) and condition for square is (it has height and width **AND** height==width) – nafas Oct 27 '15 at 11:15
  • 1
    ok so Rectangle is the superclass means that Square has stronger pre-conditions, because height and width in Rectangle can be any integer major than zero but in Square they can be only equal to each other – Francesco Oct 27 '15 at 11:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/93479/discussion-between-francesco-and-nafas). – Francesco Oct 27 '15 at 11:18
  • 2
    actually this is the typical example in which inheritance falls short: you cannot really relate them in code as you do in real world. It's somewhere in the Clean Code video series from Uncle Bob (I do not remember exactly which one) – ThanksForAllTheFish Oct 27 '15 at 12:11
  • I have a similar question here: https://softwareengineering.stackexchange.com/questions/358757/how-to-losen-input-contracts-by-inheritance I even used the same square and rectangle example somewhere else. Interesting how hard LSP is in practice. – inf3rno Oct 09 '17 at 03:41
  • I think the point by LSP that if you inherit the Square from the Rectangle class, then you will get unexpected errors by using a Square instance in a code written for a Rectangle instance. The Square has a constraint on width and hight so by setting those in your code you can get unexpected errors if they do not equal. Since the squares pass the type check for Rectangle, using LSP is the only way to ensure that the code won't break unexpectedly. Thus Rectangle can't be a base class of the Square class, because it would violate LSP. You need a different model instead. – inf3rno Oct 09 '17 at 05:18

5 Answers5

2

A general way to find out super and subclasses, you basically need to answer this question:

Is every X a Y?

In you case you need to say these two things:

  • Is every Rectangle a Square? No.
  • Is every Square a Rectangle? Yes.

Thus Square is a Rectangle. Then the condition for becoming Square is:

  • If it's a rectangle; and
  • the height equals the width.
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
nafas
  • 5,283
  • 3
  • 29
  • 57
0

You need to understand every square is a rectangle but every rectangle is not a square.

Condition you need for rectangle is its has 4 size not less not more and any three angles are 90 degrees.

In code they should be 2 different classes. I haven't defined polygon class but you get the concept of it.

Eg :

public class Quadrilateral extends Polygon {
    ...
}

Next :

public class Rectangle extends Quadrilateral {
    private double length;
    private double breadth;

   public Rectangle (double len, double brd ) {...}

}

Then square :

public class Square extends Rectangle {
    private double side;
    public Square (double sideLength) {
         super(sideLength, sideLength);
    }
}
StackFlowed
  • 6,664
  • 1
  • 29
  • 45
0

Actually it's the otherway round. Square is a SubClass of Rectangle. Why? Every Square 'is a' Rectangle, but not every Rectangle 'is a' Square.

You can extend this inheritance relation further, every GeometricShape is an Object, every Polygon is a GeometricShape, every Quadrangle is a Polygon, every Rectangle is a Quadrangle, etc. The further you go down the inheritance hierarchy, the more constraints are added, making the subclasses more special, than the parent classes.

What is a contraint of a Rectangle? Every corner has a rectangular agle (90°), what is the the constraint of a Square? Its a rectangle (90°) with every edge being of the same length.

Gerald Mücke
  • 10,724
  • 2
  • 50
  • 67
  • so in that case square must have stronger pre-condition in order to check heigth == width, so it violates the SP principles – Francesco Oct 27 '15 at 11:14
  • no, SP is not violated, whenever a Rectangle is needed, you can use a Square, but not the other way round. You can substitute any Rectangle (Baseclass) with a Square (SubClass). But when a Square is required (stronger pre condition), you can not substitute it with Rectangle (unless it's a Square). – Gerald Mücke Oct 27 '15 at 11:18
  • 1
    Ok, so Square has stronger pre-condition that is a violation of the SP principles. If S is a subclass of B, then S must have the same or weaker pre-condition of B – Francesco Oct 27 '15 at 11:23
0

Subtyping

A subclass, or child class, is always a specialized type of the base class, or superclass.

Java uses the keyword extends, because the subclass actually extends the superclass, often adds functionality.

A square is a special, that is, more specific type of a rectangle. It is a rectangle, but with the additional property that the height equals the width.


Liskov Substitution Principle

However, the Substitution Principle – I'm guessing that you mean the Liskov Substitution Principle – states that anywhere where you would expect a certain class (in our case Rectangle), you should be able to use a subtype of that class (in our case Square), without breaking the functionality or logic. If you're not, the design violates the Liskov Subtitution Principle.

I can give an example, but it is already written in this answer. Note that this answer uses the classes you mentioned.

So, to summarize, it sounds logical that a square is a specialized type of a rectangle, but according to the Liskov Substitution Principle, it is bad abstraction.

So yes, declaring Square as subclass of Rectangle fails the Liskov Substitution Principle.

Note that they also wrote a Wikipedia page about it. It's a very common problem.

Community
  • 1
  • 1
MC Emperor
  • 22,334
  • 15
  • 80
  • 130
0
  • Rectangle is subclass of Square. Reason being, rectangle is a weaker form of square: it has weaker preconditions.
  • Square preconditions: four sides, all adjoining at 90 degree, all sides equals.
  • Rectangle has only first two preconditions. Will these two behave same for client code? Yes.
  • Square: getArea() {return side*side}
  • Rectangle:
    • getArea() {return l * w} << same interface Square constructor:
  • Square(int side) Rectangle constructor 1:
  • Rectangle(int side){l = side; w = side;} << same interface as square
  • Rectangle constructor 2:
    • Rectangle(int l, int w){this.l = s; this.w = w} << new addition
  • Why is rectangle allowed to have an extra constructor? Because it extends square, and therefore can add functionality, but cannot restrain functionality of superclass.
Apurva Singh
  • 4,534
  • 4
  • 33
  • 42