7.9
Formal package parameters**
§12.7
1 Formal packages can be used to pass packages to a generic unit. The for- mal_package_declaration declares that the formal package is an instance of a given generic package. Upon instantiation, the actual package has to be an instance of that generic package.
2 formal_package_declaration ::=
withpackage defining_identifieris
newgeneric_package_name formal_package_actual_part; 3 formal_package_actual_part ::= (<>) | [generic_actual_part]
4 Thegeneric_package_name shall denote a generic package (thetemplate for the formal package); the formal package is an instance of the template.
5 The actual shall be an instance of the template. If the for- mal_package_actual_part is (<>), then the actual may be any instance of the template; otherwise, each actual parameter of the actual instance shall match the corresponding actual parameter of the formal package . . .
Composing abstractions is an important programming technique. With generic package parame- ters, you can supply one abstraction—a generic unit—with a second abstraction, without listing all the types and operations of the second abstraction as separate parameters. Section 10.8 contains an example of the direct composition of generics. Here we demonstrate the use of an empty generic package called asignatureto specify an abstraction needed by a generic unit.
Case study: generic simulation
We generalize the rocket simulation by declaring a generic simulation package that can be instan- tiated for any event type and for any priority queue implementation.
We start by declaring a Root_Event package. Note that the event type is no longer abstract, because generic events will now be put on the queue, not just events derived from the root event. The package body (omitted) contains dummy bodies for the primitive operations.
- - File: ROCKETG
1 - -
2 - - Root event
3 - -
4 packageRoot_Eventis
5 type Eventis tagged private;
6 functionCreate returnEvent;
7 procedure Simulate(E:in Event);
8 function"<"(Left, Right: Event’Class) returnBoolean;
9 private
7.9 Formal package parameters** 119
11 type Eventis tagged
12 record
13 Time: Simulation_Time;
14 end record;
15 endRoot_Event;
The next stage is to declare a signature for a generic event priority queue. The meaning of the signature is that an event priority queue isanypackage that supplies the type and subprograms declared as generic formal parameters.
16 - -
17 - - Generic event priority queue signature
18 - -
19 withRoot_Event;
20 generic
21 type Queue(Size: Positive)is limited private;
22 with function Empty(Q:access Queue)returnBoolean is<>;
23 with procedurePut(E:in Root_Event.Event’Class; Q: accessQueue)is <>;
24 with function Get(Q:accessQueue) returnRoot_Event.Event’Classis<>;
25 packageGeneric_Event_Priority_Queueis
26 endGeneric_Event_Priority_Queue;
The signature is used as a generic formal package parameter‡33for the packageGeneric_Simu- lator; the generic body uses subprogramsGet ‡50,Empty ‡49andPut ‡45from the specification of the formal parameter. In terms of the contract model, the formal parameter specifies the types and subprograms from the package available for use within the generic unit; the actual parameter must be a package that providesat leastthose types and subprograms.
27 - - 28 - - Generic simulator 29 - - 30 withRoot_Event; 31 withGeneric_Event_Priority_Queue; 32 generic
33 with packageEvent_Queueis new Generic_Event_Priority_Queue(<>);
34 packageGeneric_Simulatoris
35 procedure Add_Event(E:in Root_Event.Event’Class);
36 procedure Run;
7.9 Formal package parameters** 120
38 - -
39 - - Generic simulator body
40 - -
41 package bodyGeneric_Simulatoris
42 Q:aliasedEvent_Queue.Queue(100);
43 procedure Add_Event(E:in Root_Event.Event’Class) is
44 begin
45 Event_Queue.Put(E, Q’Access);
46 endAdd_Event;
47 procedure Run is
48 begin
49 while not Event_Queue.Empty(Q’Access)loop
50 Root_Event.Simulate(Event_Queue.Get(Q’Access));
51 end loop; 52 endRun;
53 endGeneric_Simulator;
Generic_Simulatoris instantiated in three stages! Firstly, the packagesEvent_Tree_Queueand
Event_Array_Queue ‘conveniently’ supply all the items promised by the signature. They are obtained by instantiating our familiar generic priority queue packages.
54 - -
55 - - Instantiation of event queue implemented by trees 56 - -
57 withTree_HPQ;
58 withRoot_Event;use Root_Event;
59 packageEvent_Tree_Queueis new Tree_HPQ(Event’Class);
60 - -
61 - - Instantiation of event queue implemented by arrays
62 - -
63 withArray_HPQ;
64 withRoot_Event;use Root_Event;
65 packageEvent_Array_Queue is newArray_HPQ(Event’Class);
Secondly, these packages are used to instantiate the signature to obtain Event_Queue_1 and
Event_Queue_2. The instantiation is simple because the actual subprograms are supplied by default.
66 - -
67 - - Instantiation of the signature with tree queue
68 - -
69 withEvent_Tree_Queue; use Event_Tree_Queue;
70 withGeneric_Event_Priority_Queue;
71 packageEvent_Queue_1 is newGeneric_Event_Priority_Queue(Queue);
72 - -
7.9 Formal package parameters** 121
74 - -
75 withEvent_Array_Queue;use Event_Array_Queue;
76 withGeneric_Event_Priority_Queue;
77 packageEvent_Queue_2 is newGeneric_Event_Priority_Queue(Queue);
Finally, we instantiate the generic simulator package to obtain two simulators: Simulator_1and
Simulator_2. As required by §12.7(4–5), the actual package parameters are themselves instanti- ations of the generic formal package parameters.
78 - -
79 - - Instantiation of the simulator with tree queue
80 - -
81 withGeneric_Simulator;
82 withEvent_Queue_1;
83 packageSimulator_1 is new Generic_Simulator(Event_Queue_1);
84 - -
85 - - Instantiation of the simulator with array queue
86 - -
87 withGeneric_Simulator;
88 withEvent_Queue_2;
89 packageSimulator_2 is new Generic_Simulator(Event_Queue_2);
90
Note that so far we have not said anything about the rocket! The hierarchy of events for the rocket simulation is defined in a child of Root_Event. Except for the package names, the source code for the rest of the rocket packages is unchanged and is omitted here.
91 - -
92 - - Rocket root event
93 - -
94 packageRoot_Event.Rocket_Event is
95 type Eventis abstract new Root_Event.Event with null record;
96 endRoot_Event.Rocket_Event;
The main subprogram can use both simulators. In a more realistic program, tasking would be used to run the two simulators concurrently.
97 - -
98 - - Run two simulators
99 - -
100 withSimulator_1;
101 withSimulator_2;
102 withRoot_Event.Rocket_Event; use Root_Event.Rocket_Event;
103 withRoot_Event.Rocket_Event.Engine;
104 withRoot_Event.Rocket_Event.Telemetry;
7.10 Generic children* 122