From: doug@monet.ads.com (Doug Morgan)
Subject: Re: Implementation Question
Organization: Advanced Decision Systems, Mountain View, CA 94043, +1 (415)
	960-7300
Date: Thu, 3 Sep 1992 00:23:52 GMT

In article <graham.715435125@galois> graham@maths.su.oz.au (Graham Matthews) writes:

   I was wondering about a small implementation problem I am having.
   Imagine I have two classes A and B defined as follows,

	   class A
		   instance variables a, b, c;
	   end class;

	   class B
		   subclass of class A;
		   instance variables e, f;
	   end class;

...[a) instance variable allocation and b) mathematical subtype issues]...

   graham

This is (I hope) the *standard* solution to your problem:

                               Math-A   <--- Abstract class as placeholder
                              /      \       for mathematical type of A.
a,b,c instance variables --> A        B <--- e,f instance variables

Standard inheritance mixes together the concepts underlying your a)
and b).  Only knowledge and discipline (and a bit of luck perhaps)
will stave off OO spaghetti.  It's strange but much of the OO
literature seems bent on glossing over or ignoring the distinctions
necessary for consistently handling this common problem.

Standard inheritance gives a class designer rope similar to this:

A. Command of physical implementation of instances and procedures:
 1. Instance variable memory layout.
 2. Set of procedures (generic functions, messages, virtual function
    names, etc.) that operate on instances.
 3. Particular methods to be executed by each generic function.
 4. Ability to change the values stored in the memory layouts.
 5. Ability to allocate new instances.
B. Influence over abstract denotations of instances and procedures.
 1. Abstract or mathematical type denoted by an instance.
 2. Abstract or mathematical function denoted by a generic function.
 3. Abstract definition of how the various types and functions all
    behave together.

Any decisions made for a class flow through to the subclasses.  The
question is, "can you keep from hanging yourself with this rope?"  The
answer is "yes, but not if you define instance variables first and
think about it later."

With inheritance, specifying any memory layout (i.e., A.1) reflects an
irrevocable decision that this particular layout is fundamental to the
definition of the class (and all its subclasses).  The act of
specifying an instance variable pulls you out of the context of most
any abstract considerations and places you squarely in the context of
near-assembler-level computer resource management.  Good designs tend
to deal with this level of abstraction only after a few others have
been fairly thoroughly fleshed out.  Doing otherwise is a common
source of nasty design flaws.

Care is also needed in specifying method implementations and
operations that change the abstract state of an instance.  The caution
about designing in state changes is that this focuses design attention
on the instance implementation.  If that is not the intended current
focus, another type of nasty flaws usually results. (E.g., let's say
we are considering the structural properties of a mathematical
rectangle and by some loss of concentration decide to require that
rectangle instances be mutable.  This is clearly an inappropriate
context in which to make such a design decision and that decision will
surely haunt us.)

In the above solution to the problem I mentioned an abstract class
(Math-A).  Although the term abstract class sounds nice and is
sometimes bound up with some notion of classes that don't have
instances, I am inclined to the view abstract classes as simply an
artifact of good OO design without particular significance in
themselves.  Abstract classes just happen to be those classes where
decisions of type B. and/or A.2 are of primary importance.  Abstract
classes naturally appear in reasonably direct and well organized
conceptual mappings (denotations) from instances and procedures on
instances to abstract types and (polymorphic) abstract functions on
those types.  An abstract class just declares some combination of a
new class, a set of new procedures (generic functions, etc.), and the
expected semantics of executing the procedures on instances of the new
class and other classes.

Fine-grained extensible OO inheritance graphs with minimal
implementation/semantics spaghetti tend to look like a network of
abstract classes on top followed by implementation subclasses below.
It is also possible, but potentially tricky to flip between
representation decisions and other abstract decisions.  In OO
languages without multiple inheritance (e.g., Smalltalk) or with
potentially severe efficiency problems (e.g., C++'s virtual base
concept), some compromises or further conventions will modify this
organization of classes.

doug
--------------------------------------------------------------------
Doug Morgan, doug@ads.com, (415) 960-7300
Advanced Decision Systems (a division of Booz-Allen & Hamilton Inc.)
1500 Plymouth St., Mountain View, CA 94043-1230
--------------------------------------------------------------------
Newsgroups: comp.object,comp.lang.clos