home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR9 / A9X_0610.ZIP / 9XM-INH.HLP < prev    next >
Text File  |  1993-06-10  |  13KB  |  324 lines

  1. Form S105-1092a
  2. 9XM-INH.HLP
  3.  
  4. Ada Information Clearinghouse, 1-800/AdaIC-11, 703/685-1477
  5.  
  6.                      MULTIPLE INHERITANCE IN Ada 9X
  7.  
  8.                                S. Tucker Taft
  9.                       Ada 9X Mapping/Revision Team
  10.                             Intermetrics, Inc.
  11.                              733 Concord Ave.
  12.                             Cambridge, MA 02138
  13.  
  14. This Language Study Note discusses the creation of multiple inheritance type 
  15. (semi-)lattices using the proposed Ada 9X object-oriented programming 
  16. features.  It is in part directed at programmers familiar with other 
  17. object-oriented programming languages that build in syntax for a particular 
  18. multiple-inheritance mechanism, rather than simply providing features needed 
  19. to support it.
  20.  
  21. In this discussion, we will in general use Ada 9X terminology, where every 
  22. object has a single "type," and multiple similar types (typically in some kind 
  23. of hierarchy or oligarchy) form a "class" of types.  If we want to use the 
  24. term "class" as it is used in C++ or Eiffel, we will always say "C++ class" or 
  25. "Eiffel class."
  26.  
  27. In some languages, such as Eiffel, multiple inheritance serves many purposes.  
  28. For example, there is no equivalent in Eiffel to the "include" statement of 
  29. C/C++ or the "with/use" clauses of Ada.  Therefore, to gain direct visibility 
  30. to the declarations of some other module, one must inherit from that module 
  31. (Eiffel class).
  32.  
  33. In C/C++, one can simply "include" file containing a set of type and object 
  34. definitions.
  35.  
  36. In Ada, one first identifies the external modules of interest via "with" 
  37. clauses, and then chooses selectively whether to make only the name of the 
  38. module (package) visible, or its contents (via a "use" clause).
  39.  
  40. In both Eiffel and C++, one can choose to inherit from some other type, 
  41. without making that visible to clients of the new type.  Effectively, the 
  42. linguistic multiple inheritance mechanism is being used to express not an "is 
  43. a refinement of" relationship, but rather an "is implemented using" 
  44. relationship.
  45.  
  46. Finally, there are the situations where a single type visibly inherits from 
  47. two or more other types.  In these cases, this is rarely a symmetric 
  48. situation.  Rather, one of the ancestor types is the "primary" ancestor, while 
  49. the others are typically "mix-ins" designed to augment behavior of the primary 
  50. ancestor.
  51.  
  52. Ada 9X supports multiple-inheritance module inclusion (via multiple 
  53. "with"/"use" clauses), multiple-inheritance "is-implemented-using" via private 
  54. extensions and record composition, and multiple-inheritance mix-ins via the 
  55. use of generics, formal packages, and access discriminants.
  56.  
  57. The Ada 9X mechanisms are designed to eliminate "distributed" overhead, so 
  58. that there is no added expense for the general user of the language because of 
  59. the presence of the mechanisms supporting multiple inheritance.
  60.  
  61. There are basically three distinct situations associated with 
  62. multi-inheritance mixins:
  63.  
  64.       1)    The case where the mix-in provides components and operations, and 
  65.             any overriding of these operations needs only to look at the 
  66.             components of the mix-in itself.
  67.  
  68.       2)    The case where the mix-in provides components and operations, and 
  69.             some of the overriding of these operations needs access to the 
  70.             whole object, rather than just the components of the mix-in.
  71.  
  72.       3)    Like (2), and in addition, any object with the mix-in must be able 
  73.             to be linked onto a list (or into some similar heterogeneous data 
  74.             structure) of other objects with the same mix-in.
  75.  
  76. Case (1) is handled completely in Ada 9X by a record or private extension, 
  77. with the type being mixed in (in a possibly extended form) as a component of 
  78. the record extension.
  79.  
  80. Case (2) is handled with a generic, that takes any type in a given class 
  81. (formal derived type), adds components (via extension) and operations, and 
  82. then re-exports the extended type.  The new operations have access to the 
  83. whole object, not just to the components being added.
  84.  
  85. Case (3) is handled with an access discriminant, that provides access to the 
  86. enclosing object for the operations of the mix-in, while still allowing links 
  87. through the mix-in.  Generics can also be used to simplify the definition.
  88.  
  89. Here are a few examples:
  90.  
  91. Case (1) --
  92. One has an abstract type "Set_of_Strings" and one wants to implement it by 
  93. reusing an existing (concrete) type "Hash_Table":
  94.  
  95. Here is the abstract type:
  96.  
  97.   type Set_Of_Strings is tagged limited private;
  98.   type Element_Index is new Natural;  -- Index within set.
  99.  
  100.   No_Element : constant Element_Index := 0;
  101.  
  102.   Invalid_Index : exception;
  103.  
  104.   procedure Enter(
  105.     -- Enter an element into the set, return the index
  106.      Set : in out Set_Of_Strings; 
  107.      S : String; 
  108.     Index : out Element_Index) is <>;
  109.  
  110.   procedure Remove(
  111.     -- Remove an element from the set; ignore if not there
  112.      Set : in out Set_Of_Strings; 
  113.      S : String) is <>; 
  114.  
  115.   procedure Combine(
  116.     -- Combine Additional_Set into Union_Set
  117.      Union_Set : in out Set_Of_Strings;
  118.      Additional_Set : Set_Of_Strings) is <>;
  119.  
  120.   procedure Intersect(
  121.     -- Remove all elements of Removal_Set from Intersection_Set
  122.      Intersection_Set : in out Set_Of_Strings;
  123.      Removal_Set : Set_Of_Strings) is <>;
  124.  
  125.   function Size(Set : Set_Of_Strings) return Element_Index is <>;
  126.     -- Return a count of the number of elements in the set
  127.  
  128.   function Index(
  129.     -- Return the index of a given element; return No_Element if
  130.         not there.
  131.         Set : Set_Of_Strings; 
  132.         S : String) return Element_Index is <>;
  133.  
  134.   function Element(Index : Element_Index) return String is <>;
  135.     -- Return element at given index position
  136.     -- raise Invalid_Index if no element there.
  137. private
  138.   type Set_Of_Strings is tagged limited ...
  139.  
  140. Here is an implementation of this abstract type that inherits its interface 
  141. from Set_Of_Strings, and its implementation from Hash_Table:
  142.  
  143.   type Hashed_Set(Table_Size : Positive) is 
  144.     new Set_Of_Strings with private;
  145.  
  146.   -- Now we give the specs of the operations being implemented
  147.   procedure Enter(
  148.     -- Enter an element into the set, return the index
  149.      Set : in out Hashed_Set;
  150.      S : String; 
  151.      Index : out Element_Index);
  152.  
  153.   procedure Remove(
  154.     -- Remove an element from the set; ignore if not there
  155.      Set : in out Hashed_Set;
  156.      S : String);
  157.   . . . etc.
  158.  
  159. private
  160.   type Hashed_Set(Table_Size : Positive) is 
  161.     new Set_Of_Strings with record
  162.       Table : Hash_Table(1..Table_Size);
  163.     end record;
  164.  
  165. In the body of this package, we would provide the bodies for each of the 
  166. operations, in terms of the operations available from Hash_Table.  Chances are 
  167. they don't match exactly, so a little bit of "glue" code will be necessary in 
  168. any case.
  169.  
  170. Case (2) --
  171. One has a type Basic_Window that responds to various events and calls.  One 
  172. wants to embellish the Basic_Window in various ways with various mix-ins.
  173.  
  174.   type Basic_Window is tagged limited private;
  175.   procedure Display(W : Basic_Window);
  176.   procedure Mouse_Click(W : in out Basic_Window; Where : 
  177.     Mouse_Coords);
  178.   . . . 
  179.  
  180. Now one can define any number of mix-in generics, like the following:
  181.  
  182.  generic
  183.    type Some_Window is new Window with private;
  184.      -- take in any descendant of Window
  185.  package Label_Mixin is
  186.    type Window_With_Label is new Some_Window with private;
  187.      -- Jazz it up somehow.
  188.  
  189.    -- Overridden operations:
  190.    procedure Display(W : Window_With_Label);
  191.  
  192.    -- New operations:
  193.    procedure Set_Label(W : in out Window_With_Label; S : String);
  194.      -- Set the label
  195.    function Label(W : Window_With_Label) return String;
  196.      -- Fetch the label
  197. private
  198.   type Window_With_Label is 
  199.     new Some_Window with record
  200.       Label : String_Quark := Null_Quark;  
  201.         -- An XWindows-Like unique ID for a string
  202.     end record;
  203.  
  204. In the generic body, we implement the Overridden and New operations as 
  205. appropriate, using any inherited operations, if necessary.  For example, this 
  206. might be an implementation of the overridden Display:
  207.  
  208. procedure Display(W : Window_With_Label) is
  209. begin
  210.   Display(Some_Window(W));
  211.     -- First display the window normally,
  212.     -- by passing the buck to the parent type.
  213.  
  214.   if W.Label /= Null_Quark then
  215.     -- Now display the label if it is not null
  216.        Display_On_Screen(XCoord(W), YCoord(W)-5, Value(W.Label));
  217.          -- Use two inherited functions on Basic_Window
  218.          -- to get the coordinates where to display the label.
  219.    end if;
  220. end Display;
  221.  
  222. Presuming we have several such generic packages defined, we can now create the 
  223. desired window by mixing in repeatedly.  First we declare the tailored window 
  224. as a private extension of Basic_Window, and then we define it via a sequence 
  225. of instantiations:
  226.  
  227.   type My_Window is Basic_Window with private;
  228.   . . .
  229. private
  230.   package Add_Label is new Label_Mixin(Basic_Window);
  231.   package Add_Border is 
  232.     new Border_Mixin(Add_Label.Window_With_Label);
  233.   package Add_Menu_Bar is 
  234.     new Menu_Bar_Mixin(Add_Border.Window_With_Border);
  235.  
  236.   type My_Window is 
  237.     new Add_Menu_Bar.Window_With_Menu_Bar with null;
  238.       -- Final window is a null extension of 
  239.            Window_With_Menu_Bar.
  240.       -- We could instead make a record extension and
  241.       -- add components for My_Window over and above those
  242.       -- needed by the mix-ins.
  243.  
  244. Case(3) --
  245. In this case, let us presume we have two independent hierarchies, one for 
  246. Windows, which represent areas on the screen, and one for Monitors, which wait 
  247. for an object to change, and then do something in reaction to it.  An object 
  248. that supports Monitors keeps a linked list of Monitors, and calls their Update 
  249. operation whenever the object is changed.  For example:
  250.  
  251.   type Monitor;
  252.   type Monitor_Ptr is access Monitor'CLASS;
  253.  
  254.   type Monitored_Object is tagged limited 
  255.     -- Monitored objects are derived from this root type
  256.     record
  257.       First : Monitor_Ptr;  - List of monitors
  258.       -- More components to be added by extension
  259.     end record;
  260.  
  261.   type Monitored_Object_Ptr is access Monitored_Object'CLASS;
  262.  
  263.   type Monitor is tagged limited 
  264.     record
  265.       Next : Monitor_Ptr;
  266.       Obj : Monitored_Object_Ptr;
  267.       -- More components to be added by extension
  268.     end record;
  269.   procedure Update(M : in out Monitor) is <>;
  270.     -- Dispatching operation, called when monitored object
  271.     -- is changed.
  272.  
  273. Now suppose we want to create a Window that can act as a Monitor as well as a 
  274. Window:
  275.  
  276. First we define a mix-in that is a monitor, and override its Update op:
  277.  
  278.   type Monitor_Mixin(Win : access Basic_Window'CLASS) is 
  279.     new Monitor with null;
  280.   procedure Update(M : in out Monitor_Mixin);
  281.  
  282. The body for this Update could be:
  283.  
  284.   procedure Update(M : in out Monitor_Mixin) is
  285.     -- On an Update, simply re-Display the window
  286.   begin
  287.       Display(M.Win);  -- This is a dispatching call
  288.   end Update;
  289.  
  290. Now we can "mix" this Monitor_Mixin into any window type, as follows:
  291.  
  292.   type Window_That_Monitors is 
  293.     new My_Window with record
  294.       Mon : Monitor_Mixin(Window_That_Monitors'ACCESS);
  295.     end record;
  296.  
  297. We could define a tailored Monitor mix-in that did something besides just call 
  298. the Display operation of the associated Window.  But in many cases, this 
  299. simple one will do the job.
  300.  
  301.                       -----------------------------
  302.  
  303. As these examples illustrate, Ada 9X provides support for the construction of 
  304. essentially arbitrary multiple inheritance type lattices, without having to 
  305. commit itself to a single linguistic mechanism for multiple inheritance, and 
  306. without burdening simple single-inheritance problems with the complexity and 
  307. implementation burden of linguistic multiple inheritance.
  308.  
  309.                             **********************
  310.  
  311.                        Reprinted with permission.
  312.  
  313.                  Ada Information Clearinghouse (AdaIC)
  314.                                P.O. Box 46593
  315.                        Washington, DC  20050-6593
  316.              703/685-1477, 800/AdaIC-11, FAX 703/685-7019
  317.            adainfo@ajpo.sei.cmu.edu; CompuServe 70312,3303
  318.  
  319. The AdaIC is sponsored by the Ada Joint Program Office and operated by IIT 
  320. Research Institute.
  321.  
  322.  
  323.  
  324.