Squares Aren’t Rectangles? A Common Misunderstanding of Object Oriented Design From MSDN Magazine

While reading the recent Dec 2010 issue of MSDN magazine, I found an article (Multiparadigmatic .Net, Part 4: Object Orientation) with misunderstandings on object oriented design. I was surprised that the author reached conclusions like, “squares aren’t rectangles,” and “no happy ending here.” The conclusions are based on misunderstandings of object oriented design.

Let me show you what the root problem is and how to get a happy ending. After reading this, you won’t be bothered by “squares aren’t rectangles.”

What’s the problem?

As most people already know, inheritance or generalization (I prefer the latter) is an important feature of OOD. Using it effectively can lead to a good object model and concise codebase. In an inheritance relationship, a subtype must maintain “IS-A” relationship with its super type, for example, a Student type IS-A Person. I think most people are just fine with this.

What about Square and Rectangle? For sure, squares are rectangles if we still remember what our math teachers taught us. It’s natural to put Square as a subtype of Rectangle as following: (copied from the article, pp76, it’s not necessarily in C# though.)

abstract class Shape
{
  public abstract void Draw();
}
class Rectangle : Shape
{
  public virtual int Height { get; set}
  public virtual int Width { get; set }
  public override void Draw() {
    Console.WriteLine(“Rectangle: {0} x{1}”, Height, Width);
  }
}
class Square : Rectangle
{
  private int height;
  private int width;
  public override int Height {
    get { return height; }
    set { Height = value; Width = Height; }
  }
  public override int Width {
    get { return width; }
    set { Width = value; Height = Width; }
  }
}

As you can find out, the Square has equal height and width and you would need only one attribute Edge for this like the following:

class Square : Shape
{
  public int Edge { get; set;}
  public override void Draw() {
    Console.WriteLine(“Square: {0} x{1}”, Edge, Edge);
  }
}

Now thinking of “a square is a rectangle,” people might consider how to convert a square and a rectangle. Why? Not because of what our teachers taught us, but you want to leverage methods that take Rectangle objects as parameters with Square objects. To achieve this, you need some more , mostly confusing, code for conversion.

To root cause this design problem, the author concluded that “Square aren’t rectangles. They have a lot similarity, granted, but at the end of the day, the constraints of a square don’t hold for rectangles, and trying to model one in terms of the other is based on a fallacy. It’s tempting to inherit Square from Rectangle, particularly because it lets us reuse some code, but it’s a false premise.”

Why are Squares Still Rectangles?

This Square/Rectangle design is a little challenging. The author correctly pointed out the “IS-A” relationship, which is a necessary condition for inheritance in object oriented design. But the question is, “is this enough to constitute an inheritance?”

Unfortunately it’s NOT.

To justify a new type (class), you should have something extra beyond what’s available in the super type (class). In the class definition, you will find at least one more new attribute, or method. Without this, you don’t need a new sub type at all. In other words, extensibility is a must for a good inheritance. Remember in Java, the keyword for inheritance is “extend.” It’s there for a good reason! C# should have copied the keyword in my opinion.

In Square/Rectangle case, the Square does not have any new attribute or method, so it should NOT be a new type, period. When a rectangle’s width and height are equal, it’s a square and in fact need less attribute. It does not extend, but contract. So the article got into the trouble by a wrong assumption that there should be a type called Square.

In summary, a good inheritance should have not only “Is-A” relationship, but also extensibility.

Happy Ending Here

Now you understand Square type is not needed. It’s pretty much a happy ending in most cases. If needed, I would suggest you add one more method to the Rectangle type as follows:

class Rectangle : Shape
{
 …
  public bool isSquare() {
    return Height == Width;
  }
 }

With the isSquare() method, you can easily test whether the rectangle object is a Square or not.

In some rare cases, all you need to take care of is square, then just define Square without Rectangle. It’s important to get your projects done, not the completeness of your object model in most cases unless you are designing a public API like vijava API for vast majority to use.

This entry was posted in Software Development and tagged , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. Nikita
    Posted December 26, 2010 at 1:57 am | Permalink

    >>To root cause this design problem, the author concluded that “Square aren’t rectangles. They have a lot similarity, granted, but at the end of the day, the constraints of a square don’t hold for rectangles, and trying to model one in terms of the other is based on a fallacy. It’s tempting to inherit Square from Rectangle, particularly because it lets us reuse some code, but it’s a false premise.”

    Unfortunatelly, the author of this article heven’t ever read the article of Barbara Liskov with this example.
    Also he(she) haven’t ever heart about SOLID principles of design (SRP,OCP,ISP,LSP, etc).
    As far as i see this is consequence of C# syntax sugar provided by Microsoft.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • NEED HELP?


    My consulting helps clients with virtualization and cloud computing, including VMware infrastructure automation and orchestration, vSphere management APIs, and deep product integration with hypervisors. Current training offerings include vSphere APIs training, vCenter Orchestrator training, and etc. Should you, or someone you know, need these consulting services or training, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.