From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-0.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,7638bc607ef4fdc8,start X-Google-Attributes: gid103376,public From: scott@plato.ds.boeing.com (Scott Moody) Subject: Limits for Generic Formal Package paremeters with tagged types? Date: 1996/07/18 Message-ID: X-Deja-AN: 168766878 sender: news@plato.ds.boeing.com organization: Boeing Defense and Space Group reply-to: scott@plato.ds.boeing.com newsgroups: comp.lang.ada Date: 1996-07-18T00:00:00+00:00 List-Id: Discussion on Layering and Generics and Generic Formal Package paremeters with tagged types: -------------------------------------- This is long winded, so to jump to the question about Ada-95 and generic formal parameters, proceed to ADA-95 LIMITATION at the end.. I am trying to design a way for various sub-systems to all manipulate a global database of information but in a manner that supports the object-oriented extensibility concepts. For example, this global database will have more or less fields in it based on the final configuration - but the existing sub-systems don't care except in a certain contrained way: they require that certain data fields exist during their execution. Example Class hierarchy: symbol (base class) -- attribute ID ^ vehicle_symbol (inherits from symbol) -- attribute HAS_ENGINE ^ car_symbol (inherits from vehicle_symbol) -- attribute NUMBER_WHEELS -- attribute GAS_AMOUNT Sub systems: info_manager - holder of the global data symbol_manager - manipulates the symbol part of global data vehicle_manager - manipulates vehicle, and symbol stuff car_manager - manipulates car, vehicle, and symbol stuff My problem is that once a sub-system is developed, I don't want it to be modified (accept through instantiation). -- Aside Instantiation Question: When dealing with reuse libraries, I would hope that 'abstract' interfaces - especially including generic packages, could be certified to work - even if the extraction and instantiation from the library may require re-compiling, but not modifying the physical code. In terms of packages providing abstract types, that code wouldn't need re-compilation but there are limits to the resulting flexibility. -- In general I feel the concept of Inheritance or even Multiple-Inheritance is over rated when dealing with extensibilty, but it is great for top down development. For example I can easily create an array type that is of some type T, where T is bound at 'code writing time' (eg. T is symbol, vehicle_symbol, car_symbol, etc). type all_objects_type is array(integer range <>) of symbol; .. or say of car_symbol; But when the type T is unknown until much later in the lifecycle the inheritance mechansims seem to fail. Ada provides a very powerful way to support this through the 'generic' parameter model. generic type T is new types_package.symbol with private; package info_manager is type all_objects_type is array(integer range <>) of T; global_objs : all_objects_type(1..100); -- constrain for example end info_manager; The user must instantiate this package with a 'concrete' type which must be based off the 'symbol' base type. This means a concrete type could be the 'symbol' or the 'car_symbol' or any of the other types in the symbol type hierarchy. For example: package our_manager is new info_manager(types_package.car_symbol); or package our_manager is new info_manager(types_package.vehicle_symbol); ---------- Now comes the hard part in the sub-system design: Each sub-system wants to use the same global data defined in the 'info_manager.global_objs'. How can they be guaranteed to all use the same global data-structure? In the typical top-down development, they could easily manipulate some global structure. For example a non-extensible way would be: package constrained_info_manager is new info_manager(types_package.vehicle_symbol); --- Or just a traditional non-generic constrained_info_manager The following managers would use the pre-instantiated 'info_manager'. with constrained_info_manager; --<< Constrained package symbol_manager -- can manipulate constrained_info_manager.global_objs(30).id end with constrained_info_manager; --<< Constrained package vehicle_manager -- manipulate constrained_info_manager.global_objs(30).has_engine end But it would be wrong, and checked by the compiler to do the following: with constrained_info_manager; --<< Constrained package car_manager -- CANNOT manipulate constrained_info_manager.global_objs(30).number_wheels end Since our pre-constrained 'info_manager' doesn't know about the 'car_symbol' subtype, unless 'constrained_info_manager' was instantiated with: package constrained_info_manager is new info_manager(types_package.car_symbol); This is too bad since the 'car_manager', if used in the final configuration, only wants to manipulate the same global information as the other managers. The other managers don't care if the 'car_manager' manipulates the same global since they themselves cannot manipulate information about the 'car'. (The basis of Object design.) But the requirement is that during the same execution, all managers are manipulating the same global data - possibly adding their own knowledge to the common problem. ------------ So what solution is available? In this case, the different manager packages basically want to use the same 'info_manager', but they want to make sure the manager is constrainted in the appropriate manner. Just like the 'constrained_info_manager' showed, the 'symbol_manager' wants an 'info_manager' that has 'at least' the fields necessary for manipulating symbols. The 'vehicle_manager' needs one with 'at least' the fields necessary for vehicles, and so on. Ada provides the following generic package capability (see LRM 12.6(2)): generic with package later_constrained_info_manager is new info_manager( <> ); pacakge symbol_manager is -- can maipulate later_constrained_info_manager.global_objs(30).id end; This states in Ada syntax, the same thing described in the previous paragraph: that the 'symbol_manager' needs an 'info_manager' that was previously instantiated with 'at least' the default type, shown with (<>). Ada 95 supports this concept very well, UNTIL one gets more complicated for say the 'vehicle_manager'. The following is valid Ada 95 code and does what is desired. generic with package I is new info_manager(types_package.vehicle_symbol); package vehicle_manager is .. can reference I.global_objs(30).id -- AND: .. can reference I.global_objs(30).has_engine end; Building a system with a 'symbol_manager' and 'vehicle_manager' can now be done as follows: package our_manager is new info_manager(types_package.vehicle_symbol); package our_symbol_manager is new symbol_manager(our_manager); package our_vehicle_manager is new vehicle_manager(our_manager); This produces the desired results. ------------------------- ADA-95 LIMITATION: Unfortunately Ada 95 has a problem when dealing with the next extension: the 'car_manager'. At first, the normal specification is used where 'car_manager' requires an 'info_manager' that has at least the 'car_symbol' information. generic with package I is new info_manager(types_package.car_symbol); package car_manager is .. can reference I.global_objs(30).id -- AND: .. can reference I.global_objs(30).has_engine -- AND: .. can reference I.global_objs(30).number_wheels end; So building a system that uses a 'car_manager' would involve instantiating an 'info_manager' based on at-least the 'car_symbol', and then instantiate the various sub-systems. For example: package our_manager is new info_manager(types_package.car_symbol); The following two work fine: package our_car_manager is new car_manager(our_manager); package our_symbol_manager is new symbol_manager(our_manager); But, this instantiation doesn't work: package our_vehicle_manager is new vehicle_manager(our_manager); with error: actual for "T" in actual instance does not match formal The reason is that the Ada95 LRM, 12.6(8) states that the "generic actual parameters match if they statically denote the same entity" I assume this means that the definition of 'vehicle_manager' required an 'info_manager' instantiated with 'vehicle_symbol' -- That and Nothing else! This is different that 'symbol_manager' which used the (<>) syntax allowing an actual to "be any instance of the template" 12.6(5). (There is probably a compiliation reason for this restriction, such as creating them on the stack, and if so I would be interested in knowing why.) I would have assumed (and did) that the same rules for object extension applied to generics. Basically the concept is for objects to be constrained syntactically, but allowed to be extended through inheritance. This would mean that the following 2 generics are both allowed to grow/extend but syntactically only the type information known and specified as parameters could be manipulated. (1) generic type T is new types_symbol.vehicle_symbol; package vehicle_manager is (2) generic with package I is new info_manager(types_package.vehicle_symbol); package vehicle_manager is The first case allows instantiation with any symbol rooted on 'vehicle_symbol' whereas the second requires an 'info_manager' package instantiated with 'vehicle_symbol' (not just rooted on vehicle_symbol) Ada 95's generics are very powerful when dealing with these object constraining concepts. I would just have thought that the second case be allowed to be extended - otherwise the generic package parameters are not as extensible as I would like, thereby limiting their use. --------------- I have included sample code below. Use 'gnatchop' and 'gnatmake main' for the valid program, and 'gnatmake main2' for the error. This was long-winded since it's a hard thing to describe in text. Hope I described it enough. Thanks for listening (or scrolling by..). If anyone can think of (1) whether this error is correct, or (2) other solutions to the global database problem (using Ada-95 record/array syntax, not just functions for getting/setting everything) Please let me know. Scott Moody Boeing Reuse Initiative ############## Following in code for gnat-3.05, solaris 2.4 ############## ############## specs of managers is un-important, I ############# placed variables there to have 'something' package types_package is type symbol is tagged record id : integer; end record; type vehicle_symbol is new symbol with record has_engine : boolean; end record; type car_symbol is new vehicle_symbol with record number_wheels : integer; gas_amount : integer; end record; end types_package; with types_package; generic type T is new types_package.symbol with private; package info_manager is type all_objects_type is array(integer range <>) of T; global_obj_s : all_objects_type(1..100); -- constrain for example end info_manager; with types_package; with info_manager; generic with package I is new info_manager(<>); package symbol_manager is x : integer; --.. can reference I.global_objs(30).id end; with types_package; with info_manager; generic with package I is new info_manager(types_package.vehicle_symbol); package vehicle_manager is y : integer; --.. can reference I.global_objs(30).id -- AND: --.. can reference I.global_objs(30).has_engine end; with types_package; with info_manager; generic with package I is new info_manager(types_package.car_symbol); package car_manager is z : integer; --.. can reference I.global_objs(30).id -- AND: --.. can reference I.global_objs(30).has_engine -- AND: --.. can reference I.global_objs(30).number_wheels end; with types_package; with info_manager; with car_manager; with symbol_manager; with vehicle_manager; procedure main is package our_manager is new info_manager(types_package.car_symbol); package our_car_manager is new car_manager(our_manager); package our_symbol_manager is new symbol_manager(our_manager); begin null; end main; with types_package; with info_manager; with car_manager; with symbol_manager; with vehicle_manager; procedure main2 is package our_manager is new info_manager(types_package.car_symbol); package our_car_manager is new car_manager(our_manager); package our_symbol_manager is new symbol_manager(our_manager); --But, this instantiation doesn't work: package our_vehicle_manager is new vehicle_manager(our_manager); begin null; end ;