Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Circle-Ellipse Problem (wikipedia.org)
21 points by dedalus on April 17, 2011 | hide | past | favorite | 20 comments


Circle can inherit from Ellipse if objects of both classes are immutable. The "stretch" method should return a new Ellipse. The implementation of "stretch" gets inherited into class Cicrle, so stretching a Circle yields a new Ellipse as the method signature says.

That example may look impractical. Here's a better one: define SanitizedString as a subclass of String (if your language allows that). Methods that output HTML to the client can take SanitizedStrings as input, so the type checker ensures the absence of XSS attacks. The constructor of SanitizedString could take an ordinary String and sanitize it, and that's the whole implementation of SanitizedString, because all other methods are already provided by String and none of them can break the sanitization because String is immutable. So using immutable objects allows you to write less code and get more compile-time guarantees.


Since there is no universally safe string, it would be better to call it HTMLString (different context such as SQL, e-mail headers, CLI require different types of sanitisation).

string.convertToHTML() would escape special characters as HTML entities, preserving the fact that it's just a benign text.


I think the main problem here is that OO "is-a" isn't the same thing as mathematical "is-a". A square is a rectangle, but a square cannot perform every action a rectangle can.

In the ass-backwards mutable-OO world, a rectangle "is-a" square, because it can be a square. Under the same requirements (x==y), a rectangle is a square. Any action which acts on a square will do precisely the same thing with a square rectangle which inherits from a square.

Similarly, a get-bounding-box for a rectangle inheriting from a square must always return a square box - a get-bounding-rectangle method must be created to handle the new, non-square output.

Rectangles supercede squares in every way, therefore a rectangle is-a square, and it is more. The mathematical "is-a" is essentially the reverse of this - a square is a rectangle with restrictions.


Bay Area HN readers may want to attend live a lecture by Barbara Liskov reprising her Turing Award lecture, The Power of Abstraction, on W4:15-5:30PM in Gates B01 on the Stanford Campus. This lecture is open to the public. The lecture will be live streamed and also archived for on-demand viewing. Female HN readers may want to attend a Stanford WICS reception before the talk. See http://ee380.stanford.edu for details.


I just found the talk on youtube for anyone who wants to preview it: http://www.youtube.com/watch?v=GDVAHA0oyJU


The real takeaway from the circle-ellipse problem is that mutators and conversion methods are inappropriate for use in inheritance. Essentially these operations (including stretching) are merely a more complicated form of class casting. Perhaps the worst offender of this principle is the toString() method. A class designer must not suppose that the string representation he implements should be the canonical representation of that class. Instead, he should provide the user with accessors and iterators, and provide an external string conversion function which generates the strings from these methods.


I agree that a class designer need not suppose that "the string representation he implements should be the canonical representation of that class," however if you take that line, you should not suppose that any class ought to know how to convert itself to another class. If phone numbers shouldn't know their canonical representation as strings, then why should circles know their canonical representation as ellipses?

Perhaps, as you suggest, this is a function that should be external to the instances. But I repeat myself:

http://weblog.raganwald.com/2007/10/too-much-of-good-thing-n...


I've seen people encounter this problem and say, "OO hierarchy is broken for programming." This is the wrong message to get; for many problems simple linearizable hierarchies are very useful.

What's broken is relying solely upon this mechanism to express all relationships. When your only relations are "Has" and "Is", even English would be hard pressed to express things elegantly.


English has no problems saying that a circle is an ellipse, though. Neither does math. I'd like my programming languages to be able to express math.


"is like" is not in the vocabulary in many OO languages, and that's the rub. A circle is not (in a general, behavioral sense) an elipse and can't support all the operations an ellipse is expected to do.

As for asking for expressing math, things like CL's generic methods or Haskell's typeclasses model this sort of ad hoc series of relationships much more elegantly, in my opinion.


Haskell's typeclasses are still a few hacks away from perfection :-) See the last part of this document: http://www.haskell.org/tutorial/numbers.html


The rub comes when one tries to hang behaviour on the types.


What other relations should there be? Would there be a form of "is sorta like, but..."? (Seriously, actually. This is somewhat like a mixin.)


Supports behavior/interface-of?

"X is Y" in English (and math) seems to have different implications than "X IS-A Y" does in statically typed, class-based OOP.


Yes, but that's IS-A in a very absolute way. There are all sorts of softer uses of "is" in English, often in combination with modifiers.


The existence of the circle-ellipse problem is sometimes used to criticize object-oriented programming. It may also imply that hierarchical taxonomies are difficult to make universal, implying that situational classification systems may be more practical.

I think this is why everyone was saying "reuse failed" back in the late 90's and why projects, like IBM's, to produce standard business object models failed. Shortly afterwards, folks like Ralph Johnson were saying stuff along the lines of how software reuse wasn't a failure, that it worked well, but it only worked in the small context of specific projects or applications.


So, in short: every Circle is an Ellipse; an XStretchableEllipse is a different thing from a mere static Ellipse; every Circle is not an XStretchableEllipse; and there's no such thing as an XStretchableCircle.


tl;dr - OO design, modeling, hierarchy ... all dependent on your situation. OO: Learn it, love it, add it to your toolset, but don't assume all problems are the nails to its hammer.

First thought: don't provide scaling methods - that's an operation best left to non-method functions or procedures. We scale lots of shapes in lots of ways that can make their original names less applicable.

After that, I started considering the models and their respective inheritance. If we expect the programming organizational structure to match the geometric organizational structure (e.g. circles are ellipses with the same axial lengths), then we might be thinking about the problem the wrong way. Do we model the hierarchy on the Real World or in a way that makes more sense in our library? I suppose it depends entirely on our purposes.

Sure, a circle's requirements for state are less than an ellipse, but it won't hurt to just draw a circle based on that additional state. Even the circumference and area formulas work out fine. So why, if I'm not coding for an resource-limited environment, am I creating a circle class anyway? They're all elipses anyway.


Alternative moral of the story: Mutation complicates things.


The very useful property of subtypes, i.e., that they may be substituted for their parents without causing error, is in conflict with mutable state.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: