[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: OO should break when broken
On Monday, September 1, 2003, at 10:38 PM, email@example.com
> Quoting Colin Putney <firstname.lastname@example.org>:
>> I've snipped large parts of Vesa's post, mostly because he objects to
>> the simplifications I made in order to keep my argument short, but
>> not explicitly disagree with my conclusion.
> You have tried to argue that Ellipse should be a subclass of Circle
> and I
> disagree with that. This should be very clear from my posts, but
> understanding this does require careful thought.
Thanks for clarifying that. Your discursive style seems to leave a lot
as an exercise for the reader, which I find makes understanding you
difficult. We apparently don't share many basic assumptions, so what
appears obvious to you is not at all obvious to me.
>> Again, I think shapes are not a good example to use in discussions of
>> object modeling, because the mathematical classification of shapes
>> everyone is familiar with does not map to a class hierarchy that
>> those shapes well.
> I basically disagree on this count also, because one learns a great
> more on OO by tackling an example that is fairly well defined (a few
> hundred years of exact mathematics) and requires careful thought. At
> very minimum, the classes in any OO example should have some well
> properties that one can use to formally show that subclassing makes
> (Sadly, examples in many low quality introductory OO texts use classes
> whose properties are barely defined if at all.)
Agreed. If I thought Ellipse should be a subclass of Circle, I would
also think that shapes are a good domain for examining OO modelling.
>>> Stated in another way, the essense of a subclass is to constrain the
>>> set of states of the superclass.
>> Interesting. Would you care to give an example, or explain why you
>> believe this?
> If you reread my previous post, you will find that it talks about the
> of states that objects of the superclass and the subclass may take
> take some time to understand it). The discussion about the states is a
> part of the reason why I think that the above characterization is
> basically accurate.
Actually I did read your previous post quite carefully. You made a very
formal assertion. I congratulate you the precision with which you
described it. What I don't understand us why you believe it to be true.
> It is hard to not come with an example. In fact, I find it more
> to find meaningful subclasses that are not constraining their
> in any way.
> A simple example would be a LinkedList[WithSlowSize] class that does
> cache the size (or length or number of nodes in the list) of the list
> a subclass LinkedListWithFastSize that would cache the size of the
> list in
> additional state. It is very easy to see that in
> the set of valid states of the superclass portion (the linked list
> and the set of valid states of the added state (the size or the number
> nodes in the linked list) are strongly dependent (specifically, for a
> specific length, only lists that contain exactly that many nodes are
> and for a specific list only a single length is valid) and that the
> set of
> valid states is a small proper subset of the cartesian product of the
> independent parts of the valid state.
Yes, what you say is true. But I don't see how you could characterize
this as the subclass constraining the superclass. For every valid
LinkedList, there is a valid LinkedListWithFastSize.
> On the other hand, if the added state in the subclass is independent of
> the superclass portion of the state, then there must be a change in the
> interface specification (an additional constraint) or the subclass
> simply not generally be useful.
I'm sorry, I don't understand what you mean by this. By "there must be
a change in the interface specification" do you mean that there must be
additional methods that use the additional state? If so, why would you
consider this a constraint? If there were no additional methods, why
wouldn't the subclass be useful? Can you give an example?
>> For sake of argument, assume that all the shape classes have to
>> implement a simple interface: #width, #height and #draw.
> Then, for the sake of argument, I'm given the task to implement a
> that returns the diagonal vector of a tight bounding rectangle for a
> Circle. A perfectly valid implementation of the function for Circles
> only call either #width or #height (but not both) and wouldn't work
> correctly when given an Ellipse.
A function? In what context would you want to do that? Up until now,
the discussion has been about modeling shapes in an object-oriented
language. We've seen examples in Java and Smalltalk. Are you thinking
about this in the context of a functional language?
Now if by "function" you mean a method on some other class that has to
work with circles and ellipses, I'd say that whoever gave you the task
made a bad design decision. A better way to do it would be to add
#extent to shape protocol. Circle and Ellipse would have different
implementations, yes. Polymorphism is what OO is all about.
> In fact, no matter what interface you choose, as long as the interface
> wide enough to actually make it possible to distinguish between Circles
> and Ellipses, then it is possible to come up with a perfectly valid
> function on Circles that will not work correctly when given an Ellipse.
Any such function is violating the encapsulation of the shape it's
given. It can be fixed by moving all or part of the function into
polymophic methods in the shape interface.