• No results found

§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;