Re: Clean Object Class Design -- Circle/Ellipse

From: Dmitry A. Kazakov <>
Date: Mon, 10 Sep 2001 17:24:50 GMT
Message-ID: <>

On 9 Sep 2001 20:53:00 -0700, (Bob Badour) wrote:

>> >> That a type inherits means only that methods are inherited.
>> >
>> >Type inheritance means that types are inherited. Nothing says that
>> >inheritance necessarily means method inheritance.
>> Interface inheritance. All other cases you probably mean are
>> irrelevant when no representation is considered.
>I believe that interface inheritance is more permissive than type
>inheritance; although, type inheritance implies interface inheritance.

Actually I do not know what "type inheritance" could be. One can inherit from type [interface, implementation, methods, literals etc].

>> >> What happens when a variable of the
>> >> type Circle is resized as if it were an Ellipse?
>> >
>> >Since references to represented circle values are not subtypes of
>> >references to represented ellipse values, they inherit no operations
>> >that allow such resizing. ie. A circle value inherits all operations
>> >on ellipse values, but circle variables do not inherit all update
>> >operations on ellipse variables.
>> If I dare translate it from the "ISO-ish", the above should simply
>> mean that objects accessible for update do not inherit update [inout]
>> methods.
>If you want to focus exclusively on unimportant implementation issues,
>I suppose you could, but I have no interest in such a discussion. I do
>not think such a discussion would illuminate much.

Were you see implementation issues?

>> It was the starting point of this bunch of LSP-threads in
>> comp.object months ago: "an in-subtyping faces less problems with
>> LSP". Nice, but the actual problem is that inout-subtyping is required
>> = in your "ISO-ish" we *need* to inherit update operations, because we
>> want to *reuse* them.
>I don't see how this is a problem. Why would you want to reuse
>"setFoci" on a circle variable when it has no meaning for circle

  1. Ellipse::Resize do have meaning for Circle when both parameters have same values.
  2. Disallowing an operation [= not inherit Resize for Circle] is a violation of LSP as well.

You said that the type of a Circle variable is not a subtype of an Ellipse variable. This perfectly explains all.

>Apparently, you mean that you want to reuse "setFoci" on ellipse
>variables even when the current value of an ellipse variable is a
>circle value. A well thought language that properly distinguishes
>values from variables will allow this. The resulting value of the
>ellipse variable might no longer be a circle value, but it will be a
>valid ellipse value.

It has nothing to do with a language. It is pretty possible in C++:

class Ellipse
public :

   Ellipse Resize1 (...) const;
// Instead of

   void Resize2 (...);

The problem here is that this is very inefficient for big objects. Note also that in your terminology Resize1 is a non-update method and Resize2 is an update one.

>Since the ellipse variable can contain ellipse values, the result is a
>valid value for the variable. N'est pas?

Yes, this is exactly why Circle's invariant goes broken.

>> And *this* inevitable violates LSP.
>Only in languages that apply LSP inappropriately.

No language apply LSP. A user can apply LSP in the design of his project. I very doubt that LSP can be enforced in a language of a real size and application area.

>Well, I'll continue to use the ISO/IEC standard vocabulary. If the
>comp.object community object to the standard definition, they can
>always inform the standards body of their apparent mistake.

Which mistake, of the standard body or of the community? (:-))

[ OFF-TOPIC Actually ISO bodies are even unable to spell my name properly, there is a standard for this [names] too! (:-)) I could of course inform they, but I suppose it does not worth the price of posttage stamp (:-)) ]

>I would note in passing C++ equates class with data type,

Untrue. In C++ class is a type. But there are types that are not classes.

>Smalltalk equates class with data type, Simula equates class with data type,
>Java equates class with data type, equates class with data type

I do not know. You'd better ask smalltalkers et al.

>> >> >>>>>"Most-specific type", 'declared type" and "inherited type" have meaning.
>> >> >>>>
>> >> >>>>How many types has the value 1, provided that I can derive from
>> >> >>>>integer?
>> >> >>>
>> >> >>>Integer is rational is real is complex.
>> >> >>
>> >> >>So only 4 types. What if I derive my own type? What if I call my
>> >> >>friends to derive a bit more types?
>> >> >>
>> >> >>>Natural is whole is integer.
>> >> >>>
>> >> >>>Any others you would like to propose?
>> >> >>
>> >> >>Lots. The file descriptor for instance. 1 is stdout.
>> >> >
>> >> >File descriptor is neither a subtype nor a supertype of integer. While it
>> >> >uses similar symbols, the properties of a file descriptor, including defined
>> >> >operations, are neither a subset nor a superset of the properties of
>> >> >integer.
>> >>
>> >> Did I claim that file descriptor is a subtype of integer? I said only
>> >> that it has the literal 1.
>> >
>> >You originally posited the value 1 in the context of the integer type.
>> >If you originally meant the symbol 1, you should have said that.
>> I do not know what an integer context might be. 1 is a literal.
>"How many types has the value 1, provided that I can derive from

The value 1 has exactly one type. 1 of integer has the type Integer. 1 of real has the type Real, etc.

>You called it a value and not a literal, and you provided the context
>of integer in the same sentence.
>If you had asked how many types the literal 1 has, I would have told
>you that the number is unlimited.

And I would answer that it is not so that one literal 1 has an unlimited number of types, but there is an unlimited number of literals 1 of different types.

>> >> >For instance, what does it mean to add two file descriptors?
>> >> >Substract? Multiply?
>> >>
>> >> They have no meaning, they are operations of some other unrelated
>> >> types.
>> >
>> >And values of those types are different from values of file
>> >descriptors even if they use the same symbols for some representation.
>> Of course values of different types are different even if their
>> representation, notation or what else is same. That is my point.
>Well, why didn't you just say so? I would have simply agreed.

So, let's put it as an axiom. Axiom 1:

For any x of X & y of Y, not X=Y => not x=y

>Of course, that does not change the fact that all integer values have
>multiple types -- including rational type and real type.

Axiom 2:
There is an integer value x and x of I & x of R, where I=integer type, R=real type.

Theorem 1: I=R

Proof: Let not I=R. Then according the axiom 2 there is x of I & x of R. Then according to the Axiom 1 not x = x. Therefore it is wrong that not I=R.

>> >> But nothing prevents me from making it a subtype of integer, so
>> >> that 1 + 1 be 2 = stderr.
>> >
>> >Nothing prevents you from declaring that pigs are subtypes of integer,
>> >but that does not change pigs into integers.
>> Absolutely. It only makes pigs a subtype of integer
>No, it does not do that either. It means that one can declare things
>that are nonsensical.

That is something really new. So X is a subtype of Y iff it has sense. The rest is easy, one should only define what is "to have sense".

>> which only means
>> that pigs would inherit some integer methods.
>It would not necessarily even do that. It would attempt to expand the
>range of integers to contain things that are not integers -- namely,

Making a type a subtype of another type has no influence on the base type.

>> It says nothing about
>> what a pig or integer is, or how it is represented.
>Nonsensical statements say nothing at all.

Wrong. They say nonsenses (:-))

>> Though I
>> disagree with that broad view, I am definitely sure that OO is able to
>> explain types and their relationship.
>I think that Date's work advances the state of the art in that respect
>-- or at least clarifies it.

The question was, should all types and their relationship be explained or only those [put your definition here] that are not "artefacts". I do not believe that there are pure [OO] and impure [non-OO] types.

>> >> >>Literal can be viewed as a read-only variable. Both literals and
>> >> >>constants might require elaboration (construction) if they have some
>> >> >>complex types.
>> >> >
>> >> >This describes exactly why neither literals nor named constants are values!
>> >> >They are variables constrained to a single value.
>> >>
>> >> Yes and this supports my view that values do not exist without
>> >> variables.
>> >
>> >No, it doesn't. Variables do not exist without values, which says
>> >nothing about the existence of values.
>> You said that constants, literals, variables are not values. I agreed.
>> What remains? Parameters? They are not too.
>Values are values. The variables that contain values are not.

Of course. It is like thoughts and brains. One is used to contain another. But have you seen thoughts without brains (:-))

>Since the type of a circle variable is not a subtype of the type of an
>ellipse variable, I see no reason for circle variables to inherit
>Resize. Why would it have meaning to do so?

See above.

>> Although it is impossible
>> in all OO languages I know (unfortunately), this chimera does not
>> solve the LSP problem, because there is an absolute simmetry in how
>> specialization + out-subtyping breaks LSP and generalization +
>> in-subtyping does same. Ellipse is an generalized Circle, so here you
>> are. Example: try to apply Circle's GetArea to an ellipse. This is no
>> C/E solution, and there is no one compatible with LSP.
>You are confusing yourself with implementation details. One cannot
>apply the GetArea property of a circle value to an ellipse value
>unless the ellipse value happens to be a circle value as well.

First it was about variables [which subtyping you proposed to distinguish from subtyping of values].

Second either (1) Circle variables have the type which is not a supertype of the type of Ellipse variables, or (2) Ellipse variables may use GetArea of Circle.

>> >> On which type setFoci is defined? Does it violate LSP?
>> >
>> >It is defined on "the type of a variable referencing an ellipse". It
>> >does not violate LSP.
>> Because it is not inherited. No subtyping - no LSP problems.
>Neat huh?

If you are ready to sacrifice subtyping to LSP, then well it is your choice. I believe Robert Martin have explained this point of view very clearly and many times. There is really nothing to add to:

In your "ISO-ish" it could sound like: the type of a Circle variable is not related to the type of an Ellipse variable.

>> >> >>2. void Foo (const X); is Foo an undate or non-update operation?
>> >> >
>> >> > C++... it is impossible to say, because C++ makes insufficient
>> >> >distinction between variable and value:
>> >> >
>> >> >1. Foo could update a global or static variable.
>> >> >2. Foo could be a member function that updates the variable referenced by
>> >> >"this".
>> >> >3. Foo could be a non-update operation, in which case it performs little of
>> >> >enduring use.
>> >>
>> >> From this point of view there is no non-update operations, because any
>> >> operation always has side effects [memory mapping, stack use etc].
>> >
>> >I disagree. You are again trying to introduce physical implementation
>> >irrelevancies into a discussion of the logical concept of type
>> >inheritance.
>> Why is then relevant your reference to global and static variables
>> that might be updated?
>You introduced the physical details in your question.

My question was: "void Foo (const X); is Foo an undate or non-update operation?". Where are the physical details?

>While one might
>assume that the question is irrelevant, it offered an example of how
>C++ makes insufficient distinction between values and variables. Since
>the example could just as easily be Java, it offers an example of how
>Java makes the same mistake.
>In a well thought language, the example you gave should be rejected as
>syntactically incorrect or flagged as semantically useless.

What could be syntactically incorrect the declaration of a subroutine "void Foo (const X);". Are subroutines semantically useless?

>> >The ability to distinguish a specific type from an inherited type does
>> >not change the fact that a given value can have many types.
>> The ability to distinguish value of a specific type from a value of
>> some of its bases.
>Same value, same set of types.

But yet distinguishable? Such a strange notion of "same".

>> >> Should your statement mean that any non-polymorphic subroutine is not
>> >> an issue regarding LSP and subtyping.
>> >
>> >An operation defined on values of a supertype must operate on values
>> >of all subtypes; otherwise, they are not subtypes. If you assume a
>> >non-polymorphic operation, you assume no subtypes, which makes the
>> >issue irrelevant.
>> ?
>> >> What makes you think so:
>> >>
>> >> 1. Non-polymorphic subroutines do not exist
>> >
>> >They exist for any type with no subtypes.
>> That's wrong. A non-polymorphic subroutine can be inherited.
>If it is inherited, it is polymorphic. Remember that we are discussing
>logical concepts and not physical implementations.

And the logical concept sounds: if an inherited subroutine is not polymorphic is a non-OO artefact condemned by ISO general assembly and regarded as an utmost physical representation. So far, OK (:-))

>> >> 3. Non-polymorphic subroutines never violate LSP
>> >> 4. Non-polymorphic subroutines always violate LSP
>> >
>> >Since there are no subtypes to substitute, they cannot violate LSP.
>> >LSP does not apply in this situation.
>> class Ellipse
>> {
>> public :
>> void Resize (unsigned NewXAxis, unsigned NewYAxis);
>> };
>> Resize is not polymorphic here [at least until it is not overloaded,
>> when overloading is counted as polymorphism].
>I assume the syntax you use means Resize changes variables declared as
>Ellipse variables. The language looks like C++ or Java. Both of these
>languages only demonstrate that they do not distinguish adequately
>between value and variable.

Aha, it is so that non-polymorphic subroutines in a languages [substitute] demonstrate inadequate distinguishing between values and variables. What a naughty subroutines (:-))

>They make the mistake of assuming that subtype variables should
>inherit update operations when they should not.

It is no mistake, it a possiblity. If you use this possibility [=inout-subtyping] you have a good chance to violate LSP. It is not a language property. It is the property of this particular kind of subtyping which may violate LSP. Again, no subtyping - no violation. Note also that there are other cases of subtyping when LSP is violated. Let's eradicate all of them, who will pay the bill?

>I do not count overloading as polymorphism; although, one can
>implement a crude polymorphism with overloading.

Crude or not, at least overloading never violates LSP [except for maybe wild implementations of by-name parmeter passing]

>> >> >>>Not my point. My point is: Type does not determine representation and
>> >> >>>representation does not determine type.
>> >> >>
>> >> >>Then you should explain how dispatch can work, if there is not way to
>> >> >>determine the type.
>> >> >
>> >> >Dispatch is ultimately an irrelevant implementation detail when discussing
>> >> >logical type inheritance. A DBMS might derive the type any number of ways
>> >> >just as it might derive the representation any number of ways.
>> >>
>> >> Dispatch = [run-time] selection of an implementation of some
>> >> polymorphic subprogram.
>> >
>> >Since the DBMS constructs the physical access path, it might not
>> >dispatch anything. It might implement the operation in place with the
>> >access path.
>> I am talking about the case when the type is unknown untill run time.
>> Then dispatch is *inevitable*. This [late binding] has nothing to do
>> with implementation or representation.
>Since the DBMS might leave some or all of the access path undetermined
>until runtime, it is irrelevant implementation.

So all bindings are late. A nice design decision.

>> >The DBMS has no need for IntelligentMatrix because the DBMS already
>> >performs the proposed function of the representation.
>> I am starting to want your DBMS to be the next president. (:-))
>Unfortunately, database management and executive decision are
>different tasks requiring very different attributes.

I still hope (:-))

>> >> >They have exactly the same values and exactly the same properties, including
>> >> >operations.
>> >>
>> >> Do you really believe that (int) 1 and (double) 1.0 have same
>> >> properties?
>> >
>> >Since they are different types, why should they? We were discussing
>> >multiple possible representations of a single type and not multiple
>> >types.
>> So int is not a subtype of double?
>It is, and they have different properties. For instance, a circle has
>a radius while an ellipse does not. If you recall, a subtype has a
>superset of the properties of its supertype.

But you said, I quote: "They have exactly the same values and exactly the same properties, including operations".

>> >> >>>>>>class Circle : public RosaElephant, public Ellipse {...}
>> >> >>>>>>
>> >> >>>>>>You cannot pass such circle to an ellipse method without conversion.
>> >> >>>>>
>> >> >>>>>In the specific implementation of your compiler, perhaps, but that says
>> >> >>>>>nothing about subtypes and supertypes in general.
>> >> >>>>
>> >> >>>>In which compiler it could be possible?
>> >> >>>
>> >> >>>In any compiler that fully supports polymorphism.
>> >> >>
>> >> >>How it supposed to work, provided that according to you values of
>> >> >>Circle are values of RosaElephant and simultaneously of Ellipse?
>> >> >
>> >> >Why would it not work? Variables of RosaElephant can have any value of
>> >> >Circle as well as any other value of RosaElephant. Variables of Ellipse can
>> >> >have any value of Circle as well as any other value of Ellipse. Variables of
>> >> >Circle can have any value of Circle.
>> >>
>> >> Because in this case the domain sets of RosaElephant and Ellipse would
>> >> intersect. But RosaElephant has no axis, it has a big salivous trunk
>> >> and a rose-colored bow with "Rosa" written upon it. You could try to
>> >> resize it, but it will surely take offence.
>> >
>> >Hey, it was your example not mine. If you want to criticize it as
>> >semantically inappropriate, choose a different example; otherwise, it
>> >is only a straw man.
>> It has nothing to do with semantic. It shows that multiple inheritance
>> and building new types using cartesian product is incompatible with
>> your theory.
>Unfortunately, it does not do that either. While RosaElephant has no
>axis, Circle does because it is also Ellipse. Since resize operates on
>Ellipse variables and Circle variables are not Ellipse variables, it
>should take offence. A well thought language will issue a compile-time

Do not count me as a user of that language (:-))

Dmitry Kazakov Received on Mon Sep 10 2001 - 19:24:50 CEST

Original text of this message