[comp.object] Subclassing vs. subtyping

wilk@svax.cs.cornell.edu (Michael Wilk) (10/09/89)

Several times at OOPSLA I heard references to the issue of
"subtyping" versus "subclassing."  This issue ties in with the
concept of inheritance and the concept of classes as sets.  Below
is my understanding of this issue based on what I heard at the
conference.  I do not claim to be an authority, so please correct
me where I am wrong.

A "class" serves at least two purposes: the (usually run-time)
generation of "instances" and the (usually compile-time) genera-
tion of "subclasses."  If we think of classes as sets, then
instances of that class refer to members of that set.

The meaning of a subclass is more subtle.  In Smalltalk and CLOS
(and probably others) a subclass represents a set of objects that
are extensions of objects in the original class: they have the
same instance variables and methods, and additional instance
variables and methods can be added.

This seems to me a programming construct that has no semantic
correlation to anything outside of programming.  Let us consider
an example below.  A rectangle is what you think it is; a
venetian blind is a rectangular geometric figure with additional
horizontal lines.

     Class RECTANGLE
          Instance variables HEIGHT, WIDTH
          Methods HEIGHTEN, WIDEN, AREA

     Class VENETIAN-BLIND
          Inherit from RECTANGLE
          Instance variables NUMBER-OF-SLATS
               (with HEIGHT and WIDTH inherited)
          Methods CHANGE-NUMBER-OF-SLATS
               (with HEIGHTEN, WIDEN, and AREA inherited)

In standard object-oriented languages, VENETIAN-BLIND is a
subclass of RECTANGLE, so that all VENETIAN-BLINDS are
RECTANGLES.  But ask any high school mathematics teacher if all
such shapes are rectangles and you'll hear a clear "No."  In
fact, it is quite the opposite:  VENETIAN-BLIND is the more
general class, as we have a rectangle whenever NUMBER-OF-SLATS
equals one!  The point to remember is that a rectangle consists
of four sides *and nothing more*.

One way to resolve this is to say that RECTANGLEs are not the
quadrilaterals we normally think of, but include any extensions
so long as its methods are supported in the subclasses.  Thus, we
should replace the name RECTANGLE with something like
RECTANGULAR-THING and have two subclasses: VENETIAN-BLIND and
RECTANGLE (or perhaps STRICT-RECTANGLE) where the latter is
indeed the simple geometric figure without extensions.

But there's nothing to insist that a programmer adopt this
regimen; subclassing simply doesn't enforce it.  What is more,
RECTANGULAR-THING cannot generate instances of every object in
the set of objects it represents; it can generate a STRICT-
RECTANGLE but not a VENETIAN-BLIND.  I believe C++ deals with
this by calling RECTANGULAR-THING an "abstract" class and
forbidding it from generating any instances at all.  This is an
understandable but unsatisfactory solution.

Let us now try to use subclassing to create a class that repre-
sents a restricted form of an existing class.

     Class RECTANGLE
          Instance variables HEIGHT, WIDTH
          Methods HEIGHTEN, WIDEN, AREA

     Class SQUARE
          Inherit from RECTANGLE ?
          Instance variables SIDE-LENGTH
          Methods SCALE, AREA

What happened to inheritance?  It was useless!  Since SQUARE is
more restricted than RECTANGLE we need *fewer* instance
variables, not *more* as subclassing allows.  And the HEIGHTEN
and WIDEN methods that applied to RECTANGLEs make sense only if
we allow squares to be automatically transformed into rectangles. 
It seems best to compose the class SQUARE without any references
to the class RECTANGLE; thus, any relationship between squares
and rectangles is only in the mind of the programmer.  Perhaps
that is enough?

My conclusion is that subclassing is a tool for code re-use and
does not conform to our intuitive understanding of types as sets
and subtypes as subsets, making it difficult to design classes at
a conceptual level before actual programming.

If I am incorrect then I would appreciate a re-education.  Please
include references to published books or articles as I am putting
together a paper and will need to make the appropriate citations.

Michael Wilk (wilk@cs.cornell.edu)

grover%brahmand@Sun.COM (Vinod Grover) (10/10/89)

In article <33009@cornell.UUCP> wilk@cs.cornell.edu (Michael Wilk) writes:
>This seems to me a programming construct that has no semantic
>correlation to anything outside of programming.  Let us consider
>an example below.  A rectangle is what you think it is; a
>venetian blind is a rectangular geometric figure with additional
>horizontal lines.
>
>     Class RECTANGLE
>          Instance variables HEIGHT, WIDTH
>          Methods HEIGHTEN, WIDEN, AREA
>
>     Class VENETIAN-BLIND
>          Inherit from RECTANGLE
>          Instance variables NUMBER-OF-SLATS
>               (with HEIGHT and WIDTH inherited)
>          Methods CHANGE-NUMBER-OF-SLATS
>               (with HEIGHTEN, WIDEN, and AREA inherited)
>
>In standard object-oriented languages, VENETIAN-BLIND is a
>subclass of RECTANGLE, so that all VENETIAN-BLINDS are
>RECTANGLES.  But ask any high school mathematics teacher if all
>such shapes are rectangles and you'll hear a clear "No."  

This is a classic fallacy.  You are modelling VENITIAN-BLIND as a kind of
RECTANGLE. This model would only provide you with answers that are
consistent with that view, no matter what the reality is, or what
high-school teachers think.

How is it different from the following example ? 

  type THOUGHT is record
      ...
  end record;

  function THINK(T : THOUGHT) return THOUGHT is
     ...
  begin 

     ...

  end;

Just because one uses suggestive names, does not mean that our model
reflects reality!

>                                                          In
>fact, it is quite the opposite:  VENETIAN-BLIND is the more
>general class, as we have a rectangle whenever NUMBER-OF-SLATS
>equals one!  The point to remember is that a rectangle consists
>of four sides *and nothing more*.
>
>One way to resolve this is to say that RECTANGLEs are not the
>quadrilaterals we normally think of, but include any extensions
>so long as its methods are supported in the subclasses.  Thus, we
>should replace the name RECTANGLE with something like
>RECTANGULAR-THING and have two subclasses: VENETIAN-BLIND and
>RECTANGLE (or perhaps STRICT-RECTANGLE) where the latter is
>indeed the simple geometric figure without extensions.
>
Another way to resolve this might be to not use inheritence 
and adopt the view that a VENITIAN-BLIND is an object consisting of a bunch
of rectangles satisfying a certain obvious constraint. 

>But there's nothing to insist that a programmer adopt this
>regimen; subclassing simply doesn't enforce it.  What is more,
>RECTANGULAR-THING cannot generate instances of every object in
>the set of objects it represents; it can generate a STRICT-
>RECTANGLE but not a VENETIAN-BLIND.  
This is the same as the concept of "mixins" in FLAVORS. That is classes that
are not to be used on their own but in combination with other classes. For
example a "window border" cannot be instantiated without combination with
window class. 

>                                     I believe C++ deals with
>this by calling RECTANGULAR-THING an "abstract" class and
>forbidding it from generating any instances at all.  This is an
>understandable but unsatisfactory solution.
I agree, but I believe that imposing strict object-orientation on everything
may yield unreal objects. One example I saw was in Air Traffic Control
System, where an object called  ETHER was introduced to detect collision of
Airplanes. All airplanes would send messages to the ETHER  to indicate their
current positions and other attributes. This implied ACTION-AT-A-DISTANCE. 
Now any physicist will tell you that this is all nonsense. Since the model
was not used to answer "wrong" questions it worked. 

>
>Let us now try to use subclassing to create a class that repre-
>sents a restricted form of an existing class.
>
>     Class RECTANGLE
>          Instance variables HEIGHT, WIDTH
>          Methods HEIGHTEN, WIDEN, AREA
>
>     Class SQUARE
>          Inherit from RECTANGLE ?
>          Instance variables SIDE-LENGTH
>          Methods SCALE, AREA
>
>What happened to inheritance?  It was useless!  Since SQUARE is
>more restricted than RECTANGLE we need *fewer* instance
>variables, not *more* as subclassing allows.  And the HEIGHTEN
>and WIDEN methods that applied to RECTANGLEs make sense only if
>we allow squares to be automatically transformed into rectangles. 
>It seems best to compose the class SQUARE without any references
>to the class RECTANGLE; thus, any relationship between squares
>and rectangles is only in the mind of the programmer.  Perhaps
>that is enough?
>
>My conclusion is that subclassing is a tool for code re-use and
>does not conform to our intuitive understanding of types as sets
>and subtypes as subsets, making it difficult to design classes at
>a conceptual level before actual programming.
>
I dont think so. I think that subclassing (aka inheritence) is useful in
many situaions for modelling real-world objects. Where it leads to
awkwardness one must either live with it or use other methods in
combination. 


Vinod Grover
grover@sun.com

ttwang@polyslo.CalPoly.EDU (Thomas Wang) (10/10/89)

wilk@cs.cornell.edu (Michael Wilk) writes:

>A "class" serves at least two purposes: the (usually run-time)
>generation of "instances" and the (usually compile-time) genera-
>tion of "subclasses."  If we think of classes as sets, then
>instances of that class refer to members of that set.

>The meaning of a subclass is more subtle.  In Smalltalk and CLOS
>(and probably others) a subclass represents a set of objects that
>are extensions of objects in the original class: they have the
>same instance variables and methods, and additional instance
>variables and methods can be added.

>This seems to me a programming construct that has no semantic
>correlation to anything outside of programming.  Let us consider
>an example below.  A rectangle is what you think it is; a
>venetian blind is a rectangular geometric figure with additional
>horizontal lines.

This is a very interesting point.  There are two kinds of inheritance.
The first kind is real ISA relationship, such as student-person.  You can say
with confidence that a student is a person.  The second kind is what I call
marriage of convenience, such as your example of venetian blind - rectangle.
Venetian blind is a shade, but is it a rectangle?  It is not so clear that
a venetian blind ISA a rectangle.

In this situation, the best thing to do is to allow venetian blind to
steal some functionalities from rectangle, but say that a venetian blind
is not ISA a rectangle.

I remembered someone on the net call them 'real inheritance', and
'user inheritance'.  I don't know if they are common terminalogies.

This is yet another example of an OO concept with multiple names.  We need
standard terminalogies fast!

>Michael Wilk (wilk@cs.cornell.edu)



 -Thomas Wang (There is a maniac in the bathtub!!
                            -Akane in "Ranma 1/2")

                                                     ttwang@polyslo.calpoly.edu

ahmad@icsib6.berkeley.edu (Subutai Ahmad) (10/10/89)

In article <1989Oct9.184205.20790@polyslo.CalPoly.EDU> ttwang@polyslo.CalPoly.EDU (Thomas Wang) writes:
>....  There are two kinds of inheritance.
>The first kind is real ISA relationship, such as student-person.  You can say
>with confidence that a student is a person.  The second kind is what I call
>marriage of convenience, such as your example of venetian blind - rectangle.
>Venetian blind is a shade, but is it a rectangle?  It is not so clear that
>a venetian blind ISA a rectangle.
>
>In this situation, the best thing to do is to allow venetian blind to
>steal some functionalities from rectangle, but say that a venetian blind
>is not ISA a rectangle.

What if you also had a class called "shade"? This is exactly the type 
of situation (no pun intended) where you need multiple inheritance.  
Just inherit the properties you want from shade AND rectangle.

Another way of looking at it is that the ISA relationship doesn't 
have to be an exclusive property.  A Venetial blind ISA rectangle but
it also ISA shade.

--Subutai Ahmad

hws@icsib1.Berkeley.EDU (Heinz Schmidt) (10/10/89)

In article <33009@cornell.UUCP>, wilk@svax.cs.cornell.edu (Michael Wilk)
writes:

> Several times at OOPSLA I heard references to the issue of
> "subtyping" versus "subclassing."  This issue ties in with the
> concept of inheritance and the concept of classes as sets.  Below
> is my understanding of this issue based on what I heard at the
> conference.  I do not claim to be an authority, so please correct
> me where I am wrong.
...
> One way to resolve this is to say that RECTANGLEs are not the
> quadrilaterals we normally think of, but include any extensions
> so long as its methods are supported in the subclasses. 

This is the point taken in "subtype = subset" approaches, like
Cardelli: A semantics for multiple inheritance, inf. & comp. 76, 1988
Goguen,Meseguer: Order-sorted algebra slolves the constructor-selector,
 multiple representation and coercion problem, 1987 IEEE proceedings of ???
Smolka, Nutt: order-sorted equational computation, SR 87-14, 
Univ. Kaiserslautern, 1987

These semantics do not only explain coercion

        RECTANGLE -------- HEIGHT ---> INT
          A                             A
        * |                             |
          |                             | 
        VENETIAN_BLIND --- HEIGHT ------+

which allows to "implement" VENETIAN_BLIND height in terms of 
RECTANGLE height, but also extension like the follwowing
(I assume two more RECTANGLE instance variables, X, and Y, 
defining the location):
 
        RECTANGLE -------- MOVE   ---> RECTANGLE
          A                             A |
        * |                           * | | **
          |                             | V
        VENETIAN_BLIND --- MOVE   ---> VENETIAN_BLIND

The obvious point in the above set interpretation is: a VENETIAN_BLIND 
is a RECTANGLE, hence we can apply MOVE. (**) additionaly explains
the intuitively clear point that a MOVE of a VENETIAN_BLIND results 
in a VENETIAN_BLIND at a different location, and the diagram also sheds
some light on the relation between the different objects and MOVE methods
involved. The subset interpretation implies:

(1) a VENETIAN_BLIND *IS* a RECTANGLE -- without forgetting 
    any of its instance variable values in (*),
(2) the RECTANGLE move operation -- presumable just changing
    the values of X and Y, applies to all RECTANGLES, including
    VENETIAN_BLINDs,
(3) hence the VENETIAN_BLIND move is the restriction of the RECTANGLE
    move to VENETIAN_BLINDs, or
(4) in other words, MOVE on RECTANGLE was MOVE for *ALL* rectangles
    including VBs in the first place (because it was expressed in terms
    of methods supported by all rectangles).

Obviously, inheritance is more than  coercion: it does something to the
inherited methods involved: 

	VENETIAN_BLIND MOVE(X) == **(RECTANGLE MOVE (* (X))).

It transforms this method to one that can be consistently applied to
VENETIAN_BLINDs. On the implementation level (code sharing),
this transformation is void, since the involved mappings (*,**) are 
identies -- provided the involved objects are of the proper type.

> But there's nothing to insist that a programmer adopt this
> regimen; subclassing simply doesn't enforce it.  What is more,
> RECTANGULAR-THING cannot generate instances of every object in
> the set of objects it represents; it can generate a STRICT-
> RECTANGLE but not a VENETIAN-BLIND.  I believe C++ deals with
> this by calling RECTANGULAR-THING an "abstract" class and
> forbidding it from generating any instances at all.  This is an
> understandable but unsatisfactory solution.

In the above setting, the constructors of RECTANGLEs (like NEW_RECTANGLE
or what has your favorite OO language) are all constructors of the set of
RECTANGLE subtypes including RECTANGLE itself. In fact each class with a 
constructor has both aspects: the set of all instances created by the
respective constructor (I'd prefer the term "essential rectangles") and
the unions of all the subtypes (here, say, "abstract rectangles").
 
>
...
> What happened to inheritance?  It was useless!  Since SQUARE is
> more restricted than RECTANGLE we need *fewer* instance
> variables, not *more* as subclassing allows.  And the HEIGHTEN
> and WIDEN methods that applied to RECTANGLEs make sense only if
> we allow squares to be automatically transformed into rectangles. 

The choice of instance variables partly is a matter of taste.
I believe at the heart of OO programming is the understanding that
instance variables, in general, are *not* independent.  In general 
a method will operate on a couple of variables. So I disagree. Are 
you saying a square doesn't have a width? Or that it doesn't have a 
height? It has both of them, whatever you choose to represent them. 
And when I ask my little son whether he can widen and heighten a square,
the answer is a clear "yes". In the above setting you might say, a SQUARE
is a rectangle with the constraint

		 HEIGHT=WIDTH 

(some OO languages allow to express such constraints). Again the
"subtype = subset"
diagram  above helps me understand the relation between the involved
WIDEN methods.
SQUARE WIDEN must preserve the constraint, because it must return a 
SQUARE. You might say, there is no obvious way to extend the RECTANGLE WIDEN
method such that it satisfies this requirement. Well, there's redefinition
beside inheritance. In some OO languages you could even reuse the
RECTANGLE WIDEN
method and hook onto it a "after WIDEN" method that adjusts the Y instance
variable upon a call to WIDEN. In other words you tell the compiler more
details about (**) and the compiler produces an efficient "combined method" 
for SQUARE without forcing you to obscure the semantic relation between the
different WIDENs involved.

> My conclusion is that subclassing is a tool for code re-use and
> does not conform to our intuitive understanding of types as sets
> and subtypes as subsets, making it difficult to design classes at
> a conceptual level before actual programming.

I disagree. The subset interpretation is intuitive. It can also be used
to explain more complex situations of subtyping (like the above SQUARE
constraint)
in a satisfactory manner. But one must not confuse it with the independent
constructor aspect involved.

-- Heinz Schmidt      hws@icsi.berkeley.edu

eberard@ajpo.sei.cmu.edu (Edward Berard) (10/10/89)

wilk@svax.cs.cornell.edu (Michael Wilk) writes:
> 
> A "class" serves at least two purposes: the (usually run-time)
> generation of "instances" and the (usually compile-time) genera-
> tion of "subclasses."  If we think of classes as sets, then
> instances of that class refer to members of that set.

I think you have missed the original intention of classes. A class is
a template, pattern, or description which represents an abstraction of
a category of items, characteristics, or metrics. A class is a
mechanism for gathering together the common attributes of a number of
very similar items. You might say that a class is a means of
describing and encapsulating the essence of a collection of very
closely-related items, characteristics, or metrics.

In "real life" we use classes to help us manage complexity. For
example, if we understand what an airplane is, we may say things like
"Boeing 747s, McDonnell Douglas DC-80s, and Piper Cubs are all
airplanes." We may even say that "they are all the same class of
entity." We may go even further, and point out that there is more than
one Boeing 747, and that "Boeing 747" really represents a class of
very similar airplanes, which have all the characteristics of
airplanes, and some additional characteristics which serve to both
identify them as Boeing 747s and to differentiate them from, say,
Piper Cubs.

Depending on the programming language we are using, we have various
ways of capturing the essence of a class. Some programming languages
provide an encapsulation mechanism, e.g., Smalltalk's classes, which
allows us to syntactically and semantically bind together all of the
sub-concepts which represent our abstraction of the real world class.
These languages also provide a few, very simple, mechanisms for
representing different aspects of the real world category of items.
For example, depending on the language, we may have available to us
such things as operations, concurrency, exceptions, and a number of
mechanisms for representing knowledge of state.

In a nutshell, classes are a mechanism for capturing concepts, and
objects (i.e., items created using classes as the patterns) are
realizations of the concepts.

> 
> The meaning of a subclass is more subtle.  In Smalltalk and CLOS
> (and probably others) a subclass represents a set of objects that
> are extensions of objects in the original class: they have the
> same instance variables and methods, and additional instance
> variables and methods can be added.

Once again, in real life, subclasses represent refinements in our
categorization process. When we say that a Ford is a kind of
automobile, we are defining a subclass. Specifically, we mean that
Fords possess all of the characteristics of automobiles, and that
Fords possess additional characteristics which serve to uniquely
identify them as Fords.

Without much effort, we can make some additional observations:

	- Subclasses are refinements of superclasses. Specifically,
	  superclasses represent broader, more general concepts, and
	  subclasses represent specializations on these concepts. Said
	  another way, superclasses represent higher levels of
	  abstraction than do subclasses.

	- What makes a given class a subclass or a superclass is its
	  context. For example, automobile is a superclass with
	  respect to Ford, and a subclass with respect to "modes of
	  transportation." [Depending on our choice of programming
	  language, we are often forced to specify the immediate
	  superclass when we are defining a new class, but we are
	  seldom, if ever, required to define all the possible
	  subclasses.]

	- In real life, we allow that a subclass (or subcategory) may
	  modify, as well as extend, the characteristics of the
	  superclass. For example, we might say that all automobiles
	  have 4 wheels, but then allow for special cases where some
	  automobiles have 3 wheels, and others have 6 wheels.

	  We speak of subclasses "inheriting" characteristics from
	  their respective superclasses. In many cases the inheritance
	  is "wholesale" inheritance, i.e., _all_ of the inheritable
	  characteristics of the superclass are inherited. In some
	  special cases, we allow for "selective" inheritance, i.e.,
	  there is some mechanism which allows us to chose which
	  characteristics we wish a subclass to inherit.

	- In real life we also allow for subclasses to acquire
	  characteristics from more than one superclass. The most
	  common example is biological, i.e., we inherit
	  characteristics from both of our parents. This is most
	  commonly referred to as multiple inheritance.

> This seems to me a programming construct that has no semantic
> correlation to anything outside of programming.

Subclasses truly reflect real life.

> Let us consider
> an example below.  A rectangle is what you think it is; a
> venetian blind is a rectangular geometric figure with additional
> horizontal lines.
> 
>      Class RECTANGLE
>           Instance variables HEIGHT, WIDTH
>           Methods HEIGHTEN, WIDEN, AREA
> 
>      Class VENETIAN-BLIND
>           Inherit from RECTANGLE
>           Instance variables NUMBER-OF-SLATS
>                (with HEIGHT and WIDTH inherited)
>           Methods CHANGE-NUMBER-OF-SLATS
>                (with HEIGHTEN, WIDEN, and AREA inherited)
> 
> In standard object-oriented languages, VENETIAN-BLIND is a
> subclass of RECTANGLE, so that all VENETIAN-BLINDS are
> RECTANGLES.  But ask any high school mathematics teacher if all
> such shapes are rectangles and you'll hear a clear "No."  In
> fact, it is quite the opposite:  VENETIAN-BLIND is the more
> general class, as we have a rectangle whenever NUMBER-OF-SLATS
> equals one!  The point to remember is that a rectangle consists
> of four sides *and nothing more*.

There are a number of comments I can make on the above:

	1. All objects have state. [I recognize that some programming
	   approaches attempt to recognize "functional objects," i.e.,
	   "stateless objects." However, for purposes of the immediate
	   discussion, I will chose to ignore them.] How this state is
	   maintained is not relevant to those interacting with the
	   object. What is important is that an object posses
	   knowledge of its state.

	   Some programming languages, e.g., Smalltalk, provide
	   special mechanisms for storing state information, e.g.,
	   instance variables. However, an object's state may also be
	   determined (calculated) on an as-needed basis, e.g., what
	   is the current velocity of a vehicle object. An object's
	   state may also be maintained outside of an object, e.g.,
	   some of the state information for a bank account object may
	   be maintained in a database.

	2. As others have pointed out, class Venetian_Blind is more
	   properly represented as a collection of rectangles. In the
	   context of the Venetian_Blind class, these rectangles are
	   referred to as "slats."

	   In object-oriented terminology, the Venetian_Blind class is
	   a homogeneous composite class, i.e., it is a composite
	   class (a class defined as an aggregation of other
	   (component) classes) whose components are _conceptually_
	   all of the same class.

> 
> One way to resolve this is to say that RECTANGLEs are not the
> quadrilaterals we normally think of, but include any extensions
> so long as its methods are supported in the subclasses.  Thus, we
> should replace the name RECTANGLE with something like
> RECTANGULAR-THING and have two subclasses: VENETIAN-BLIND and
> RECTANGLE (or perhaps STRICT-RECTANGLE) where the latter is
> indeed the simple geometric figure without extensions.

Given my previous comments, I would not recommend this approach.

> But there's nothing to insist that a programmer adopt this
> regimen; subclassing simply doesn't enforce it.  What is more,
> RECTANGULAR-THING cannot generate instances of every object in
> the set of objects it represents; it can generate a STRICT-
> RECTANGLE but not a VENETIAN-BLIND.  I believe C++ deals with
> this by calling RECTANGULAR-THING an "abstract" class and
> forbidding it from generating any instances at all.  This is an
> understandable but unsatisfactory solution.

What you are talking about here is sometimes referred to as "partial
types." Partial types represent important, but incomplete concepts.
For example, in everyday life, we speak of dogs. However, there is no
single dog for which the concept of a dog is a _complete_ description.
We usually create subclasses of dog, e.g., German_Shepard, Beagle, and
Poodle, to more completely describe a given dog. (Even this amount of
subclassing may be insufficient, e.g., there are many different kinds
of Poodles.)

Partial types are extremely useful. They allow us to gather, in one
place, a set of common characteristics, i.e., characteristics which
are common to all of the subclasses of the partial types. For example,
in developing a user interface capability, we may create a "window
class," but never create an instance of this class. We may, however,
create instances of the subclasses of the window class, e.g., text
windows and graphics windows.

Partial types serve a number of uses:

	- They allow us to localize and encapsulate a set of highly
	  logically related (cohesive) characteristics which support a
	  single, object-oriented concept. We use this idea in
	  everyday life, e.g., all dogs have the following
	  characteristics ... . Think about how difficult life would
	  be if you could never refer to "airplanes in general," "the
	  concept of shapes," or "a category of occupations."

	- From the standpoint of organizing an application in an
	  object-oriented manner, partial types spare us the drudgery
	  of having to constantly repeat a set of common
	  characteristics. (Think of how many keystrokes you'll save.
	  ;-))

> 
> Let us now try to use subclassing to create a class that repre-
> sents a restricted form of an existing class.
> 
>      Class RECTANGLE
>           Instance variables HEIGHT, WIDTH
>           Methods HEIGHTEN, WIDEN, AREA
> 
>      Class SQUARE
>           Inherit from RECTANGLE ?
>           Instance variables SIDE-LENGTH
>           Methods SCALE, AREA
> 
> What happened to inheritance?  It was useless!  Since SQUARE is
> more restricted than RECTANGLE we need *fewer* instance
> variables, not *more* as subclassing allows.  And the HEIGHTEN
> and WIDEN methods that applied to RECTANGLEs make sense only if
> we allow squares to be automatically transformed into rectangles. 
> It seems best to compose the class SQUARE without any references
> to the class RECTANGLE; thus, any relationship between squares
> and rectangles is only in the mind of the programmer.  Perhaps
> that is enough?

Mathematicians tell us that "squares are simply special cases of
rectangles," and that "circles are simply special cases of ovals."
What makes squares different from rectangles, and circles different
form ovals, is that restrictions are placed on the states squares and
ovals may assume. This is yet another way in which a subclass may
differ from its superclass, i.e., subclasses may place restrictions on
the states that their instances (objects created using the subclass)
may assume.

Using the examples of the square and rectangle classes, we could say
the following:

	- Squares still have "height" and "width." However, there is a
	  restriction that these two pieces of state information have
	  equal values.

	- The operations of "heighten" and "widen" are still present
	  in squares. However, the methods (i.e., the internal
	  implementations of the operations) have been altered. For
	  example, heighten now changes the state of "width" as well
	  as the state of "height."

	- The method for the operation of "area" for a square is
	  identical to the method for the operation of "area" in the
	  class rectangle.

	- Although we recognize that the height and width of a square
	  are identical, we may not wish to replace them with a single
	  piece of state information, e.g., side_length. Consider the
	  situation where we are examining a number or rectangles to
	  determine which of them are "true squares." This touches on
	  the essence of many discussions concerning the differences
	  between classes and types, e.g., should one be allowed to
	  compare squares and rectangles in the same expression?

	- Why did you supply a "scale" operation for class square, but
	  not for class rectangle? 

> My conclusion is that subclassing is a tool for code re-use and
> does not conform to our intuitive understanding of types as sets
> and subtypes as subsets, making it difficult to design classes at
> a conceptual level before actual programming.

My observation is almost exactly the opposite. Subclassing does
provide for some low-level reuse. (There is much more to software reuse
than merely "robbing code" from superclasses.) All too often I run
into people who cannot separate concepts from implementation, e.g.,
they cannot explain the concept of inheritance outside fo the context
of their favorite object-oriented programming language.

In the classes I teach, more than one person has observed that I am
attempting to convey a method of thinking about a problem (i.e., an
object-oriented approach) which can be applied equally-well to
hardware, human organizations, and source code implementations. If
people do not understand object-oriented thinking before they write
their first program, it will be even more difficult to separate
concepts from implementations at a later date.

> If I am incorrect then I would appreciate a re-education.  Please
> include references to published books or articles as I am putting
> together a paper and will need to make the appropriate citations.
> 

For a more detailed discussion of partial types, see:

[Halbert and O'Brien, 1987]. D.C. Halbert and P.D. O'Brien, "Using
Types and Inheritance in Object-Oriented Programming," IEEE Software,
Vol. 4, No. 5, September 1987, pp. 71 - 79.

For a discussion of "types vs. classes," see, for example, the recent
discussions taking place on comp.lang.smalltalk involving Alan Wills
(Manchester University, UK), Paul R. Wilson (Software Systems
Laboratory, University of Illinois), Ralph Johnson (University of
Illinois), and Robert Dew (Australia). I would recommend that you
contact Ralph Johnson (johnson@cs.uiuc.edu) as a starting point. (Be
sure to ask about Typed Smalltalk.)

				-- Ed Berard
				   Phone: (301) 353-9652
				   FAX:   (301) 353-9272

hallett@pet3.uucp (Jeff Hallett x5163 ) (10/11/89)

In article <33009@cornell.UUCP> wilk@cs.cornell.edu (Michael Wilk) writes:
>The meaning of a subclass is more subtle.  In Smalltalk and CLOS
>(and probably others) a subclass represents a set of objects that
>are extensions of objects in the original class: they have the
>same instance variables and methods, and additional instance
>variables and methods can be added.

Basically, subclasses perform two logical functions:

  1.  The allow for specification of task
  2.  They provide semantic differentiation

Either may (or may not)  require more instance  variables.  Either may
(or may not) require more messages.  

It is possible to have an abstract class.   Such  a class has instance
variables and  defines active messages,  but has no methods and cannot
generate objects.  Its sole  purpose   is to serve    as a  point   of
specification or differentiation in the inheritance tree and act  as a
starting point for the classes that will actually do the work.

>Let us now try to use subclassing to create a class that repre-
>sents a restricted form of an existing class.
>
>     Class RECTANGLE
>          Instance variables HEIGHT, WIDTH
>          Methods HEIGHTEN, WIDEN, AREA
>
>     Class SQUARE
>          Inherit from RECTANGLE ?
>          Instance variables SIDE-LENGTH
>          Methods SCALE, AREA
>
>What happened to inheritance?  It was useless!  Since SQUARE is
>more restricted than RECTANGLE we need *fewer* instance
>variables, not *more* as subclassing allows.  And the HEIGHTEN
>and WIDEN methods that applied to RECTANGLEs make sense only if
>we allow squares to be automatically transformed into rectangles. 
>It seems best to compose the class SQUARE without any references
>to the class RECTANGLE; thus, any relationship between squares
>and rectangles is only in the mind of the programmer.  Perhaps
>that is enough?


This is true,  but consider  that  a  square is  a  rectangle  with an
additional constraint upon it.  It has every property that a rectangle
has but has  an EXTRA one  - it is  a semantic  specification.  If you
send area! to   a square or  a  rectangle,  you expect  the  area - it
doesn't matter what it is. When you create a square, you also create a
rectangle - it just happens that  this rectangle has all  of its sides
equal.  Note also that a rectangle can be scaled, so scale!  should be
a message to rectangle as well as square.   If  I ask a square for its
height, I expect to get its height, just like any other rectangle.


Subclasses  are   an intuitive device that allow   you  to  modify the
behavior of  the original class  to create  a  more specific  form  or
function.  My  general guideline  for creating  subclasses  is  really
wrapped up in a few questions:

1.  Do  I need something  that  is similar, has  the same data, but is
just a little different?  Y == subclass.

2.  If I write a method and I have to ask the question, "Am I a..." or
"Do I have the property of...", I write a subclass (usually).

3.  Do I have a logical counterpart in  the real world  whose behavior
is  convenient to  model that lives  in an ISA  relationship with some
other class?  Y == subclass.  


--
	     Jeffrey A. Hallett, PET Software Engineering
      GE Medical Systems, W641, PO Box 414, Milwaukee, WI  53201
	    (414) 548-5163 : EMAIL -  hallett@gemed.ge.com
     "Your logic was impeccable Captain. We are in grave danger."