§7.2
2 package_body ::=
package body defining_program_unit_nameis
declarative_part [begin
handled_sequence_of_statements]
end[[parent_unit_name.]identifier];
6 For the elaboration of a nongeneric package_body, its declarative_part is first elaborated, and itshandled_sequence_of_statementsis then executed.
6.5
Class-wide types
Now that we have declared types for the events in the simulation, we can return to the problem of constructing a queue that can store events of different types. A data structure that contains items of more than one type is calledheterogeneous, as opposed to ahomogeneousdata structure whose elements are all of one type. We cannot create a heterogenous data structure containing items of arbitrary type; this would not be compatible with the strong type checking of Ada. Instead, the design of Ada chooses a flexible intermediate approach: objects of all types derived from a parent type can be stored in a data structure. The specific type of an object is checked, if necessary, when it is used at run-time.
§3.4.1
4 Class-wide types—Class-wide types are defined for (and belong to) each derivation class rooted at a tagged type (see 3.9). Given a subtype S of a tagged type T, S’Class is thesubtype_markfor a corresponding subtype of the tagged class-wide typeT’Class. Such types are called “class-wide” because when a formal parameter is defined to be of a class-wide typeT’Class, an actual parameter of any type in the derivation class rooted atTis acceptable (see 8.6).
Given the derivation class of types shown in Figure 6.2, the values of the typeEvent’Classare the union of the values of all the derived types in the class. As noted in the last sentence of §3.4.1(4) above, if a formal parameter is of class-wide type, the actual parameter can be of any type in the class. For example, the function"<" in packageRoot_Event ‡12takes two parameters of the class-wide typeEvent’Classso it can be called with actual parameters of any event type. Of course, the body of the function‡98–101can only reference components common to all types in the class.
However, you can’t simply declare an object of a class-wide type:
EC: Event’Class; - - Error!
Recall the analogous situation with unconstrained array types such asString. It is not possible to declare an uninitialized variable or a record component of the type. However, an object can be of unconstrained type provided that it will be supplied with a constraint upon elaboration:
S1: String; - - Error! S2: String := "Hello world"; - - OK
6.5 Class-wide types 78
type String_Pointer is accessString; - - Pointer to string of any length
P: String_Pointer := newString(1..80); - - OK, see §4.8
type String_Recordis record F1: String; - - Error! F2: String(1..80); - - OK F3: String_Pointer; - - OK end record;
function Palindrome(S: String)returnString; - - Create a palindrome from a string of any length
Unconstrained array types and class-wide types areindefinite types.
§3.3
23 . . . A subtype is an indefinite subtype if it is an unconstrained array subtype, or . . . ; otherwise the subtype is adefinitesubtype (all elementary subtypes are definite subtypes). A class-wide subtype is . . . an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional constraint or explicit initializationexpressionis necessary (see 3.3.1). A component cannot have an indefinite nominal subtype.
The implications for the design of a heterogeneous priority queue are as follows. ThePutproce- dure‡225is declared with a parameter of class-wide type so that an event of any type in the class can be inserted into the queue, and theGetfunction‡226returns a result of class-wide type so that an event of any type can be removed from the queue. Here is the specification of the package for a heterogeneous priority queue of events:
218 withRoot_Event;use Root_Event;
219 packageEvent_Queue is
220
221 type Queue is limited private;
222 type Queue_Ptris access Queue;
223
224 functionEmpty(Q: in Queue)returnBoolean;
225 procedure Put(E:in Event’Class; Q:in outQueue);
226 functionGet(Q: Queue_Ptr) returnEvent’Class;
227 228 private 229 - - 230 - - Implement as tree. 231 - - 232 type Node;
6.5 Class-wide types 79 234 type Queue is 235 record 236 Root: Link; 237 end record; 238 239 endEvent_Queue;
A node of the queue cannot directly contain an item of class-wide type; instead,Node contains
‡248a pointer to the event‡244(Figure 6.3).
Data Left Right @ @ R - Time Fuel Oxygen Main_ Engine_ Event
Figure 6.3: Node of a heterogeneous tree
The data structure is encapsulated in the body of the package, which is adapted from the final version of the priority queue package.
240 package bodyEvent_Queue is
241
242 - - Heterogeneous data cannot be directly stored in Node.
243 - - Store a pointer to the data.
244 type Event_Class_Ptris access Event’Class;
245
246 type Nodeis
247 record
248 Data: Event_Class_Ptr;
249 Left, Right: Link;
250 end record;
251
252 procedure Put(E:in Event’Class; Node_Ptr: in outLink)is
253 begin
254 ifNode_Ptr =null then
255 Node_Ptr := newNode’(newEvent’Class’(E),null,null);
256 elsif E < Node_Ptr.Data.all then
257 Put(E, Node_Ptr.Left); 258 else 259 Put(E, Node_Ptr.Right); 260 end if; 261 endPut; 262
6.5 Class-wide types 80
263 procedure Put(E:in Event’Class; Q:in outQueue)is
264 begin
265 Put(E, Q.Root);
266 endPut;
267
268 functionEmpty(Q: in Queue)returnBoolean is
269 begin
270 returnQ.Root =null;
271 endEmpty;
272
273 procedure Get(Node_Ptr: in outLink; Found: outLink)is
274 begin
275 ifNode_Ptr.Left = null then
276 Found := Node_Ptr; 277 Node_Ptr := Node_Ptr.Right; 278 else 279 Get(Node_Ptr.Left, Found); 280 end if; 281 endGet; 282
283 functionGet(Q: Queue_Ptr) returnEvent’Classis
284 Found: Link;
285 begin
286 Get(Q.Root, Found);
287 returnFound.Data.all;
288 endGet;
289
290 endEvent_Queue;
An object of typeEvent’Classis allocated and initialized by copying the data fromE. The access to the object is used to initialize theDatacomponent of the allocated node‡255.Node_Ptr.Data
must be explicitly dereferenced‡256in order to compare it with inserted eventE. Similarly, to return a value of typeEvent’Class,Found.Datamust be dereferenced‡287.
How to avoid indirect allocation*
An alternative approach is to derive the entire class from the data structure for the node:5 type Nodeis tagged
record
Left, Right: Link;
end record;
type Eventis new Node with null record;