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)