
Circle-Ellipse Problem - dedalus
http://en.wikipedia.org/wiki/Circle-ellipse_problem
======
cousin_it
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.

~~~
pornel
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.

------
Groxx
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_.

------
drallison
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.

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

------
codehero
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.

~~~
raganwald
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...](http://weblog.raganwald.com/2007/10/too-much-of-good-thing-not-
all.html)

------
KirinDave
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.

~~~
cousin_it
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.

~~~
KirinDave
"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.

~~~
cousin_it
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>

------
stcredzero
_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.

------
qntm
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.

------
delinka
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.

~~~
eru
Alternative moral of the story: Mutation complicates things.

------
Tyr42
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.

