comp.lang.ada
 help / color / mirror / Atom feed
* Limits for Generic Formal Package paremeters with tagged types?
@ 1996-07-18  0:00 Scott Moody
  1996-07-19  0:00 ` Robert I. Eachus
  1996-07-21  0:00 ` Robert A Duff
  0 siblings, 2 replies; 3+ messages in thread
From: Scott Moody @ 1996-07-18  0:00 UTC (permalink / raw)




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 ;







^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Limits for Generic Formal Package paremeters with tagged types?
  1996-07-18  0:00 Limits for Generic Formal Package paremeters with tagged types? Scott Moody
@ 1996-07-19  0:00 ` Robert I. Eachus
  1996-07-21  0:00 ` Robert A Duff
  1 sibling, 0 replies; 3+ messages in thread
From: Robert I. Eachus @ 1996-07-19  0:00 UTC (permalink / raw)




In article <DurCzM.7v2@plato.ds.boeing.com> scott@plato.ds.boeing.com (Scott Moody) writes:

   > 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.

   This is not an easy one, but the problem is that you have fixed on
a certain method of combining abstractions and inheritance.  To solve
your problem you need to use class-wide types and dispatching in the
info_manager.  However, you seem to want to create an array of fixed
size objects.  Ada won't allow you to do this directly, since the
maximum size of the all objects of the class can't be known.  So you
have to do Unchecked_Conversions inside of the info manager--if you
insist on an array of fixed sized objects.

   If you want to stay at a high level, the answer is to have your
info_manager manage an array of class-wide pointers.  You can then
have dispatching operations to allocate and free these pointers, and
assuming I know where you are coming from, all the designated objects
will be created once, during initialization, and there will be no use
of the heap:

    type Symbol is abstract tagged null record with private;
    type Pointer is access all Symbol;
    ...
    procedure Free(P: in out Pointer);
    -- the body of Free will dispatch based on the type of P.all.
    -- there is no allocate function declared, since Ada rules would
    -- require overriding in all cases, and you will normally want to
    -- have different parameters for each allocate.
  private
    type Symbol is ...
    -- Note that you will need fields in Symbol to be used by the
    -- info_manager, and will want to have initial values for them.
    -- This could be as little as a single In_Use bit, or a pointer to
    -- self. 
    procedure Manage(S: in out Symbol) is abstract;
    -- called by Free to do type specific operations.

-- In another package...
    type Vehicle_Symbol is new Symbol with private;

  private
    Vehicle_Array: array(1..N) of Vehicle_Symbol;
    -- there only can be N objects of type vehicle symbol.  However
    -- this does not include car_symbols which will be found in their
    -- own (private) array.
    
  Sketchy, and includes a lot of things like anonymous arrays I
wouldn't use in real code, but it should give you the idea.  You can
make the info_manager a generic, but there is no need to.  It's
differences in behavior will come through inherited operations.

--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Limits for Generic Formal Package paremeters with tagged types?
  1996-07-18  0:00 Limits for Generic Formal Package paremeters with tagged types? Scott Moody
  1996-07-19  0:00 ` Robert I. Eachus
@ 1996-07-21  0:00 ` Robert A Duff
  1 sibling, 0 replies; 3+ messages in thread
From: Robert A Duff @ 1996-07-21  0:00 UTC (permalink / raw)



In article <DurCzM.7v2@plato.ds.boeing.com>,
Scott Moody <scott@plato.ds.boeing.com> wrote:
>
>Discussion on Layering and Generics and Generic Formal Package paremeters
>with tagged types:
>...

I apologize if I don't fully understand your question, but it sounds
like what you want is an array of Symbol'Class.  But that's not allowed
-- Ada wants all array elements to be of the same size.  So what you
need to do is have an array of Symbol_Ptr, where type Symbol_Ptr is
access all Symbol'Class.

I don't really see how the generic-ness in your example makes any
difference to this point -- maybe I'm missing the point.

- Bob




^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~1996-07-21  0:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-07-18  0:00 Limits for Generic Formal Package paremeters with tagged types? Scott Moody
1996-07-19  0:00 ` Robert I. Eachus
1996-07-21  0:00 ` Robert A Duff

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox