[comp.lang.eiffel] Rectangular Polygons?

YTHNMADD@MTUS5.BITNET (Noel Maddy) (03/01/91)

At the risk of resurrecting a dead horse just to beat it some more,
there may be another way of looking at this POLYGON / RECTANGLE debate.

It seems to me that much of the problem comes from lumping two
separate concepts into _inheritance_: extension and restriction.
I think that we have a method of inheritance that has been optimized
for extension, and we are trying to use the same method for restriction.

Consider the POLYGON/RECTANGLE debate:  A rectangle is not an extension
of a polygon, but rather a restriction (i.e., it is a polygon with
four sides and right angles).  As a result of these restrictions of
form, we also must restrict possible actions on the rectangle
(e.g., we cannot add a vertex to a rectangle and still have it be
a rectangle).

A solution which has not been proposed can be created from a
separation of extension and restriction.

Using the POLYGON/RECTANGLE situation as an example, we can see:

   1)  A RECTANGLE meets the invariant of a POLYGON
   2)  A RECTANGLE cannot perform the add_vertex operation while
          remaining a RECTANGLE  (i.e., satisfying its invariant)
   3)  A POLYGON _can_ perform the add_vertex operation at all times

Thus it seems that we need a way for anything which has been declared
as a POLYGON to add_vertex, but prevent anything which has been
declared as a RECTANGLE to add_vertex.  While I know very little
concerning the current implementation of Eiffel, couldn't you have
the compiler reject any r.add_vertex, but accept any p.add_vertex?
Since only PLYGONs will have vertices added, and POLYGONs cannot
be reassigned to RECTANGLEs, this should guarantee that a vertex is
not added to a RECTANGLE.  It seems like you could do this by simply
not declaring add_vertex as exported in RECTANGLE.  The only implementation
question would be whether add_vertex was accessible for a RECTANGLE
instance at run-time which is contained in a POLYGON variable.

To represent this in the language would require some extension:
Add a _restrict_ clause to a class which would take the place of the
_inherit_ clause in a restriction situation.  I think this should be
restricted to having only one ancestor, although it is conceivable
that you could combine extension and restriction in one class by
restricting more than one class.  This _restrict_ clause should be
allowed to redefine and/or rename features from its ancestor.

The _invariant_ clause would contain the restrictions which were
applicable to the new class.  Although it may be possible to
have the compiler check all features of the ancestor to find those
that would change the restricted variables, it would be simpler
(although more work for the programmer) to remove the offending
features from the _export_ clause.

This does present the spectre of dynamically changing the class of
an instance, however.  For instance:

   p : POLYGON;
   r  : RECTANGLE;
   ...
   p := r;
   p.add_vertex(...);

would require the run-time system to convert the RECTANGLE instance into
an equivalent POLYGON instance.  To simplify this, it would be necessary
to put a restriction on any restricted classes that no new stored
features be added.  This agrees with the intuitive concept of a class
restriction, however.  Again, I am unsure of the current implementation
of Eiffel, but if the class of an instance is stored as a pointer to
some class structure, this should not be too hard to do.

Example:

class POLYGON export
   add_vertex, ...
feature
   ...
   add_vertex (vertex : POINT) is do
      ...
   end;
invariant
   -- 3 or more vertices
end  -- class POLYGON

class RECTANGLE export
   ..., diagonal, ...
   -- add_vertex is not exported
restrict
   POLYGON
      redefine perimeter -- easier to calculate
feature
   ...
invariant -- could call this restriction, but I hate adding keywords
   vertices.nb_elements = 4
   -- diagonals are equal (i.e., right angles)
end -- class RECTANGLE

I can envision complex extensions to this, such as adding  _promote_
and _demote_ clauses to allow extra stored features to be added in
the restriction step and tell how these features are mapped when
an instance is moved from the general to the restricted class.
(another interesting ability would be to have the run-time system
check the restrictions (invariants) of all subordinate classes to
determine whether an instance could be moved from the general class to
the restricted class, but this seems like too much of a run-time
penalty for the advantages it would give).

Well, now that I have exhausted about a month's pent-up thought on
this, what do you gurus think?  Is this possible/desirable, or am
I missing something basic?  Please comment.

---
Noel Maddy         (YTHNMADD@MTUS5.BITNET)