• No results found

3.7

Parameter modes

Most programming languages define a parameter-passing mechanism such as call-by-value or call-by-reference. In call-by-value, the value of the actual parameter is copied into the variable denoted by the formal parameter, whereas in call-by-reference, the formal parameter contains a pointer to the actual parameter. In Ada, each parameter has amodeassociated with it that defines the permitted uses of the parameter,notthe parameter-passing mechanism. (Parameters can also be passed asaccess parameters; see Section 9.5.)

in The formal parameter is considered to be aconstant §3.3(17), and the actual parameter is an

expression§6.4.1(4) that is used to initialize the constant. This is the default mode if none is specified. Functions may only haveinparameters.

out The formal parameter is an uninitialized variable §6.4.1(15). The actual parameter must be avariable. Anoutparameter can be used to pass data from the subprogram to the calling program.

in out This is like anoutparameter, except that the formal parameter is initialized with the value of the actual parameter.

In the fill-and-justify case study, Get_Word uses outparameters ‡19–21 in order to pass data back to the calling program. Put_Wordusesinparameters‡89–90for the word to be appended and its length, andin outparameters‡91–93for buffer state that is manipulated in the procedure. As a matter of style, I explicitly writeinfor parameters of procedure declarations even though it is the default mode, because it helps document the data flow to and from the procedure. I do not writeinmode for function parameters; since a function can only havein parameters, there is no decision here to document.

The formal parameter of the functionPalindromeis of typeString, which is an unconstrained array subtype. The rules of parameter passing §6.4.1specify that the actual parameter isconvertedto the formal parameter. An unconstrained target takes its constraints from the source §4.6(38), so the function can be called with any string.

Strange: String(17..27) := "Hello World"; Put(Palindrome(Strange));

will print"Hello WorlddlroW elloH". Of course, this only works because we were careful to use attributes rather than absolute values for the array index expressions in the subprogram.

It is important to understand the trade-offin the Ada design: in order to allow you to write gen- eralized subprograms,compile-time type checking of array bounds has been traded forrun-time

checking of constraints. By using attributes in expressions, the bounds of the actual parameters need not be explicitly passed.

3.7 Parameter modes 33

Implementation of parameter modes**

The three parameter modes in, out andin out, are defined in terms of use rather than imple- mentation. However, the ARM does specify most aspects of the implementation, and you will occasionally need to be aware of these details.

§6.2

2 A parameter is passed eitherby copyorby reference. When a parameter is passed by copy, the formal parameter denotes a separate object from the actual parameter, and any information transfer between the two occurs only before and after executing the subprogram. When a parameter is passed by reference, the formal parameter denotes (a view of) the object denoted by the actual parameter; reads and updates of the formal parameter directly reference the actual parameter object.

3 A type is aby-copy typeif it is an elementary type, . . . . A parameter of a by-copy type is passed by copy.

4 A type is aby-reference typeif it is . . .

10 A parameter of a by-reference type is passed by reference. . . .

11 For parameters of other types, it is unspecified whether the parameter is passed by copy or by reference.

Thus numbers, enumerations and pointers are passed by copy. We have not yet studied types that are passed by reference, but these are types such as tasks that represent internal data structures rather than ‘normal’ data.

What is most important is the last sentence §6.2(11): the language does not specify if arrays and records are passed by copy or by reference. By aliasing two parameters, or a parameter and a global variable, it is not difficult to create a procedure whose result depends on the implementation. Such a program is not portable, and you should avoid such programming techniques.

4

Elementary Data Structures

This chapter is an introduction to the construction of data structures in Ada using arrays, records and access types (pointers). Data structures are normally implemented as abstract data types using packages and private types to be discussed in the next chapter. The case study is the implementa- tion of a priority queue, first using arrays and then using pointers.

4.1

Case study: array priority queue

A priority queue is a data structure that stores items in such a way that retrieval the of ‘highest- priority’ item is can be done efficiently, even if insertion of items will be less efficient. In the case study, we assume that the items are simply integers and that higher-priority items have lower values. This is a common situation: customers in a store take numbered tickets and the lowest outstanding number is served first.

The operations supported by the queue are: Get the lowest number, Put a new number in the queue, and check if the queue is Empty.1 AGet operation from an empty queue will raise the exceptionUnderflowand aPutoperation to a full queue will raise the exceptionOverflow.

- - File: PROGPQA

1 - -

2 - - Priority queue implemented as an array.

3 - -

4 withAda.Text_IO; use Ada.Text_IO;

5 withAda.Integer_Text_IO; use Ada.Integer_Text_IO;

6 procedure ProgPQAis

7

8 type Vectoris array(Naturalrange <>)of Integer;

9 type Queue(Size: Positive)is

10 record

11 Data: Vector(0..Size); - - Extra slot for sentinel

12 Free: Natural := 0;

13 end record;

14

15 Overflow, Underflow: exception;

16

1Style: the operations are intended to be read ‘put item on queue’ and ‘get item from queue’, and this can be for- malized using named parameter associations (Section 4.3). Putting the queue parameter first would be more consistent with languages for object-oriented programming that use distinguished-receiver syntax (Appendix A).

4.1 Case study: array priority queue 35

17 functionEmpty(Q: in Queue)returnBoolean is

18 begin

19 returnQ.Free = 0;

20 endEmpty;

21

22 procedure Put(I:in Integer; Q: in outQueue)is

23 Index: Integer rangeQ.Data’Range := 0;

24 begin

25 ifQ.Free = Q.Size then

26 raise Overflow;

27 end if;

28

29 - - Sentinel search for place to insert

30 Q.Data(Q.Free) := I;

31 whileQ.Data(Index) < I loop 32 Index := Index+1;

33 end loop;

34

35 - - Move elements to free space and insert I

36 ifIndex < Q.Free then

37 Q.Data(Index+1..Q.Free) := Q.Data(Index..Q.Free-1); 38 Q.Data(Index) := I; 39 end if; 40 Q.Free := Q.Free+1; 41 endPut; 42

43 procedure Get(I:outInteger; Q:in outQueue) is

44 begin 45 ifQ.Free = 0 then 46 raise Underflow; 47 end if; 48 I := Q.Data(0); 49 Q.Free := Q.Free-1; 50 Q.Data(0..Q.Free-1) := Q.Data(1..Q.Free); 51 endGet; 52

53 Q: Queue(10); - - Create queue of size 10

54 I: Integer; - - Element of the queue

55 Test_Data: array(Positiverange <>)of Integer :=

56 (10, 5, 0, 25, 15, 30, 15, 20, -6, 40);

57 58 begin

59 forNin Test_Data’Range loop

60 Put(Test_Data(N), Width => 5);

61 Put(Test_Data(N), Q);