Re: Clean Object Class Design -- Circle/Ellipse

From: Dmitry A. Kazakov <dmitry_at_elros.cbb-automation.de>
Date: Sun, 09 Sep 2001 18:34:53 GMT
Message-ID: <3b9b8545.1636346_at_news.cis.dfn.de>


On 8 Sep 2001 15:36:59 -0700, bbadour_at_golden.net (Bob Badour) wrote:

>dmitry_at_elros.cbb-automation.de (Dmitry A. Kazakov) wrote in message news:<3b94d133.1837081_at_news.cis.dfn.de>...
>> On Tue, 4 Sep 2001 03:14:31 -0400, "Bob Badour" <bbadour_at_golden.net>
>> wrote:
>>
>> >>>If we accept your assumption that no such thing as subtype exists, we can
>> >>>end this conversation now. The conversation is, after all, a discussion of
>> >>>subtype.
>> >>
>> >>How the view that any value has a type disallows subtypes?
>> >
>> >The view that any value has one and only one type disallows inherited type,
>> >which then disallows supertypes and subtypes.
>> >
>> >Any value has a specific type and possibly many inherited supertypes.
>>
>> 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.

>> >If one properly recognizes the type difference between variables and values,
>> >LSP poses no problem. A variable is a reference to a representation of a
>> >value, which makes its type different from that of the value whose
>> >representation it references.
>>
>> How it helps in the case of LSP.
>
>Apply LSP to subtype/supertype relationships. While a circle value is
>a subtype of an ellipse value,

[Value is not a subtype]

> a reference to a represented circle
>value is not a subtype of a reference to a represented ellipse value.

[Reference being a value is also not a subtype]

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

[Is that ISO terminology, that value *is* a subtype and *inherits* something?]

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. 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. And *this* inevitable violates LSP.

>The OO programming world took existing vocabulary from other
>disciplines and restricted the meaning -- much as those other
>disciplines took vocabulary from the english language and restricted
>the meaning.
>
>Before you can redefine the meaning of the word for the OO programming
>community, you must establish a consensus among its members.
>Currently, that community generally equates class with data type as
>evidenced by the ISO standard vocabulary for programming languages.

You may ask the community whether it accepts that class = type [I wouldn't do it (:-))], alternatively try google search for this topic in comp.object.

>> >>>>>"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. You claimed that there is only 4 types it might have. I argued that there may an unlimited number of 1s 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.

>> 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, which only means that pigs would inherit some integer methods. It says nothing about what a pig or integer is, or how it is represented.

>> >Again, I must point out that your example uses an artifact from a non-object
>> >oriented system.
>>
>> Maybe the artifact is that a particular system is unable to explain
>> what appears "artefact"? I wouldn't blaim OO for this.
>
>I never did blame OO for this. I only stated that your non-OO example
>is inappropriate for a discussion of OO.

Some people find OO appropriate to explain the whole universe, not only its unmeasurably small fraction called programming. Though I disagree with that broad view, I am definitely sure that OO is able to explain types and their relationship.

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

>> >>Value of an ellipse cannot be resized because the result [in most
>> >>cases] is another value.
>> >
>> >One cannot resize an ellipse value because values do not change -- ever. One
>> >can resize an ellipse variable because variables do change.
>>
>> "Resize" means "to call a routine named Resize with an actual
>> parameter which value is of ellipse type".
>
>Since "Resize" changes the actual parameter, one must pass a variable
>-- not a value. Since a circle variable is not an ellipse variable,
>one cannot pass it.

Which means that one cannot inherit and so reuse Resize. This is what I meant saying that the cure is worse than the disease.

>No. As Jan pointed out, "the type of a variable referencing a circle"
>is a supertype of "the type of a variable referencing an ellipse".

Aha. So your proposal is to make Circle an in-subtype and simultaneously inout-supertype of Ellipse. 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.

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

>> >>2. void Foo (const X); is Foo an undate or non-update operation?
>> >
>> >...in 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?

>> >>There is no dynamic polymorphism without tags. So being non-existing
>> >>it would not work, which should wake up some interest of the user.
>> >
>> >Try to think out of the box a little. It is possible -- you just haven't
>> >imagined all of the possibilities.
>>
>> Which ones?
>
>Consider that the DBMS might at different times choose different
>access paths. Such a choice is dynamic. In one path, the DBMS might
>know that it always uses one representation for a type, and in another
>path, the DBMS might know that it always uses a different
>representation. Once the DBMS dynamically chooses a specific access
>path, it has no need for tags.
>
>Again, tags are an irrelevant implementation detail. Internally the
>DBMS must somehow represent the meta-data governing which physical
>representation and type a specific variable has, but this is
>irrelevant to the discussion of the logical concept of
>subtype/supertype.
>
>This is the last time that I will discuss tags. I have address that
>they are irrelevant to the discussion, and I will ignore any mention
>of them from this point forward.

As you wish.

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

>> >>>In my language, -1 is a literal of real type also.
>> >>
>> >>Then they are two different literals overloaded in some given context.
>> >
>> >Nope. A single literal has multiple types.
>> >
>> >>One -1 has the type Integer another -1 is Real.
>> >
>> >Nope. The single literal has both type Integer and type Real.
>>
>> Now please, explain this:
>>
>> type MyInteger is new Integer; [Specifies representation for a new type]
>> A : Integer := -1; -- Literal of what? [Integer]
>> B : MyInteger := -1; -- Literal of what? [MyInteger]
>> B:=A; -- Compilation error - why? [Unrelated types]
>
>Using an example that confuses type with representation proves little
>of utility.

How type is confused with representation in above?

>> >In either case, discussing a function from a non-object oriented language
>> >like C says nothing about object orientation.
>>
>> As far as I know the discussion was about C/E problem and subtypes.
>
>It was until you hijacked it with myriad irrelevancies.

My apologies

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

>> 2. Non-polymorphic subroutines cannot be inherited
>
>They would then be polymorphic -- by definition.

Which definition?

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

>> >>So I made the conclusion you argued that the
>> >>representation determines the type. Or it is the type that determines
>> >>the representation. In any case, to distinguish types by
>> >>representation there should be a mapping representation->type. This
>> >>excludes multiple type representations.
>> >
>> >Type does not determine representation. Physical representation does not
>> >determine type. Internally, the dbms must represent the metadata information
>> >regarding type and representation, but does not expose this internal
>> >representation to any user. This allows multiple representations for the
>> >same type.
>>
>> It is exposed in dispatch.
>
>Assuming dispatch -- which I do not.

As you wish

>> >>>I can accept that provided we accept that representation is orthogonal to
>> >>>type.
>> >>
>> >>It is, in the sense that a user/compiler is free to choose a
>> >>representation for a type. But the choice shall be made.
>> >
>> >You assume that a single choice will be made, but the assumption is false.
>> >In order to provide physical independence, the dbms must allow multiple
>> >representations for a type.
>>
>> Which union is the actual and single representation of the type.
>
>No. Physical independence requires that we allow multiple alternate
>representations for a type.

I do not see how it requires that. The single observable way is to prove that this set [union] does not exist [cannot be built].

>> >>Value is a language term here.
>> >
>> >What language? What is wrong with the generally accepted definition? How
>> >does the definition as a "language term" differ?
>>
>> Values in a language are not mathematical objects they might
>> occasionaly represent.
>
>First, I need to clarify a faulty assumption: Values are not
>necessarily mathematical.
>
>Again: What language? What is wrong with the generally accepted
>definition? I do not see how values in a language are any less
>abstract. Physical representations are physical representations, and
>values are values. Let's not confuse the two.

Where you see a confusion? The representation is determined. Not only what and how is stored in the memory cells, but also the distribution of electron smoke in the semi-conductors is determined. The systems we are talking about are finite and deterministic, at least they are considered as such.

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

>> Provided that implementations are written by
>> the user, how could it be irrelevant which one is selected?
>
>Here is a fundamental misunderstanding. When one assumes physical
>independence, one does not assume that the ultimate implementation is
>written by the user. One assumes quite the opposite.

Ultimative implementation is of no interest as well as the color of the box running that ultimative implementation. Implementation is what a user writes. A polymorphic subprogram may have several implementations in exactly that sense, i.e. written by some users. It is a definition of a polymorphic subprogram.

>> It is very doubtful that
>> whether to declare a variable DenseMatrix or SparseMatrix is
>> irrelevant if the matrix is 100,000x100,000.
>
>Since each will obviously lead to very different performance
>characteristics, and since those performance characteristics will
>depend on many potentially unpredictable factors including data
>distribution and context of use, the DBMS should choose based on which
>representation will perform the given task better.

Egh, you know, it is halting problem. But if your DBMS have solved that, let it write programs instead of us. Let's close comp.object and sample post stamps. (:-))

>> It is also thinkable to
>> have some IntelligentMatrix which would try automatically get an
>> advantage from the distribution of non-zero elements, but in any case
>> those three are different types.
>
>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. (:-))

>> >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?

>> >>>>And how do you call the set of all values having exactly one [of that
>> >>>>multiple] representation. I would call it a type. And you?
>> >>>
>> >>>I call it the empty set. All of the values have both representations.
>> >>
>> >>Simultaneously? So the representations are undistinguishable = same.
>> >
>> >Yes. At the logical level, the cartesian representation of Complex(0,1) is
>> >indistinguishable from polar representation of Complex(1,Degrees(90)).
>>
>> Which means that there is exactly one representation.
>
>Internally, there are two representations. Externally, there is a
>single type.

What happens internally is no mater.

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

Regards,
Dmitry Kazakov Received on Sun Sep 09 2001 - 20:34:53 CEST

Original text of this message