Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!bloom-beacon!usc!randvax!florman From: florman@randvax.UUCP (Bruce Florman) Newsgroups: comp.lang.eiffel Subject: Deferred routines and name clashes Message-ID: <1981@randvax.UUCP> Date: 24 Apr 89 23:49:35 GMT Organization: Rand Corp., Santa Monica, Ca. Lines: 102 I recently came across a problem with multiple inheritance and deferred routines which, while not insurmountable, can only be handled by some ugly, inefficient, and possibly non-portable programming practices. I am writing a small discrete-event simulation, and one of the most primitive classes is the LOCATABLE class, which is used to represent physical objects whose location may be expressed as a single point. One of the exported routines of LOCATABLE is a deferred routine named `location' which returns an object of type POINT. There are three heirs to LOCATABLE which provide alternative implementations of the location routine. The first is the INDEPENDENT_ LOCATABLE class, which simply stores the location in an attribute named `current_location'. The second is the DEPENDENT_LOCATABLE class, which defines an attribute named `host' of type LOCATABLE, from which it gets its location. This allows me to represent things which are discrete objects, but which are attached to other locatable objects, generally ones which can move. The last heir to provide an effective definition of the location routine is the SEMI_DEPENDENT_LOCATABLE class, which inherits from both INDEPENDENT_LOCATABLE and DEPENDENT_LOCATABLE. Its definition returns its current_location attribute if its host is void, and returns its host's location otherwise. This allows the represen- tation of objects which are only sometimes attached to other objects. Another class which inherits from LOCATABLE is the class called TWO_WAY_RADIO, which is used to represent things which both transmit and receive radio signals. A TWO_WAY_RADIO must be LOCATABLE so that the simulation can determine such things as whether any two of them are close enough together to receive each other's signals, but the actual implementation of the location routine is of no concern to the TWO_WAY_RADIO class. Since there exist large radio installations whose location is pretty well fixed (INDEPENDENT_LOCATABLE), and radios which are bolted into cars and boats and planes (DEPENDENT_LOCATABLE), and portable radios which may be passed from one person to another (SEMI_ DEPENDENT_LOCATABLE), we don't want to tie TWO_WAY_RADIO directly to any of those classes. The problem arises when I try to define an effective class which inherits from TWO_WAY_RADIO. When I try to define, for example, SQUAD_CAR_RADIO -- the radio installed in a police car -- simply as an heir to both TWO_WAY_RADIO and DEPENDENT_LOCATABLE, the compiler complains about a name clash, despite the fact that the name coming from one parent has no effective definition, and the name coming from the other parent is simply a definition of the very same deferred routine. The work around for this problem is simple, but stupid. The class is defined as shown below. class SQUAD_CAR_RADIO ... inherit DEPENDENT_LOCATABLE; TWO_WAY_RADIO rename location as radio_location feature ... radio_location: POINT is do Result := location end; ... end -- class SQUAD_CAR_RADIO It certainly seems pointless and inefficient that every time any of the TWO_WAY_RADIO routines accesses the location, it will have to go through this glue routine. It seems especially pointless that, given the above definition, any routines which are effectively defined by classes above TWO_WAY_RADIO in the inheritance graph will also have to go through this glue routine whenever they access the location. This is because, as I pointed out in another posting a couple of weeks ago, when an entity's dynamic class has more than one effective definition for a given routine, the definition from the last parent in the inheritance clause takes precedence, regardless of whether it has been renamed. However, this inefficiency can be eliminated by simply reversing the order of DEPENDENT_LOCATABLE and TWO_WAY_RADIO in the inheritance clause above. I still haven't heard from ISE whether this should be considered an implementation dependent feature of Eiffel (maybe when people get back from Paris). In _Object-oriented_Software_Construction_, Dr Meyer emphasizes the concept of deferred classes as partial implementations of abstract data types. It would seem to be consistent with this idea that two deferred classes which each implement half of the abstract type may be combined in a straight forward manner to fully implement that data type. I feel that a more perfect Eiffel compiler would recognize the case where a name clash arises from one parent effectively defining an inherited routine that another parent doesn't. It would accept the inherited definition as the effective definition for both parents, possibly issuing a warning similar to the one issued for repeated inheritance. Undoubtedly there will be cases where the above behavior is not desirable, so probably there should be a method that allows the programmer to prevent the compiler from merging the definitions. Perhaps this would be done by explicitly resolving the clash through renaming. Aside from its exorbitant cost and the fact that it isn't available for the Macintosh environment, I'm still a great fan of Eiffel. However it does still have some weaknesses, and it would be nice to see them addressed in future releases. -- Bruce Florman florman@rand.org