• No results found

procedure Put(Item: in Integer; Into: in outQueue); Put(Item => Test_Data(N), Into => Q);

The advantage of this style is improved readability; a disadvantage is that the source code can become too ‘wordy’.

One problem with named association is that the parameter names create a dependence between the subprogram specification and the caller of the subprogram that would not otherwise exist. That is, we cannot change the formal parameter names without changing every call that uses named association!

Default parameters are extensively used in libraries where you want to supply many options, but default values are sufficient for most uses. For example,Ada.Integer_Text_Putis declared §A.10.8(11) as:

procedure Put( Item: inNum;

Width:inField := Default_Width;

Base: inNumber_Base := Default_Base);

Normally, you would print an integer in the default field width and the default base (decimal). Either or both can easily be changed:

Put(N, Width => 5); - - From ‡69 Put(N, 5); - - Equivalent

Put(N, Base => 16); - - Print in hexadecimal

Default parameters can cause difficulty in overloading resolution. Given the following two proce- dure declarations, the callProc(5)is ambiguous:

procedure Proc(N: in Integer; K: inInteger := 10);

procedure Proc(M: in Integer);

4.4

Declaring and raising exceptions

The case study declares two exceptions‡15:

Overflow, Underflow: exception;

Unlike predefined exceptions that are raised by the run-time system, exceptions that you declare must be explicitly raised using araisestatement‡26,46.

§11.4

3 When an exception occurrence is raised by the execution of a given construct, the rest of the execution of that construct is abandoned; that is, any portions of the execution that have not yet taken place are not performed. . . . Then:

5 If the construct is the sequence_of_statements of a handled_sequence_of_- statementsthat has a handler with a choice covering the exception, the occurrence is handled by that handler;

4.4 Declaring and raising exceptions 40

In the country of origin case study, the exception was handled in the same subprogram where it was raised. Here we demonstrate another possibility:propagatingthe exception to the caller.

§11.4

6 Otherwise, the occurrence ispropagatedto the innermost dynamically enclosing execution, which means that the occurrence is raised again in that context.

8 Note that exceptions raised in adeclarative_partof a body are not handled by the handlers of thehandled_sequence_of_statementsof that body.

If you try to Get from an empty queue, the Get subprogram can only diagnose the problem. It cannot know if you did this on purpose, nor can it know what action is appropriate in this situation. (This will become clear in the next chapter, where you will learn how to encapsulate the queue.) Thus we do not handleOverflowandUnderflowwhere they are raised; instead, they are propagated to the caller—in this case the main subprogram—and are handled there by printing an error message‡75–77.

The following program demonstrates what is meant by thedynamically enclosing execution. P3 ‡8–11is statically nested withinP1, but since it is called byP2 ‡14, the handler inP2 ‡16, rather than the handler inP1 ‡21, will be executed.

- - File: PROP

1 - -

2 - - Propagating an exception.

3 - -

4 withAda.Text_IO; use Ada.Text_IO;

5 procedure Propis 6 Ex: exception; 7 procedure P1is 8 procedure P3is 9 begin 10 raise Ex; 11 endP3; 12 procedure P2is 13 begin 14 P3; 15 exception 16 whenEx => Put("Handled in P2"); 17 endP2; 18 begin 19 P2; 20 exception 21 whenEx => Put("Handled in P1"); 22 endP1; 23 begin 24 P1; 25 endProp;

If no handler is found, the run-time system handles the exception, usually by terminating the program and printing a message. In an embedded system, you would want to handle all possible exceptions, because termination and printing are not viable system behaviors.

4.4 Declaring and raising exceptions 41

A certain amount of judgement is needed when using exceptions. Exceptions can almost always be avoided by using explicit if-statements and additional parameters; conversely, Ada novices often replace too many if-statements by exceptions. A good rule-of-thumb is to use exceptions for states that should rarely, if ever, occur. In our case study, you would normally check that a queue is empty before calling Get, and you would normally declare the queue to be sufficiently large to contain all the data that you intend to store. Neither overflow nor underflow should ever occur. It is worth noting that exceptions by themselves do not ensure reliability. It is difficult to plan for unexpected situations and even more difficult to test them. A good case study of exception handling can be found in the report on the failure of the first test of the Ariane 5 rocket (Lions 1996). One of the causes of the failure was the incorrect design of an exception handler, which shut down the navigation computers instead of taking corrective action.

Optimization and Suppress**

Transformations performed by the compiler for the purpose of optimization may subtly effect the semantics of a program. For example, in the following program fragment, a compiler could ‘optimize away’ the creation of the variableS, provided thatSis not used elsewhere in the program. In doing so, the compiler has ‘optimized away’ the exception that would be raised as a result of assigning’G’, the result ofChar’Succ(’F’), to a value of subtypeSub:

subtypeSub isCharacter range’A’..’F’; S: Sub := Char’Succ(’F’);

C: Character := S;

A second possibility is that in moving code for purposes of optimization, an exception may not occur exactly at the place you expect.

§11.6gives an implementation permission to perform such optimizations.

§11.5

2 Alanguage-defined check(or simply, a “check”) is one of the situations defined by this International Standard that requires a check to be made at run-time to determine whether some condition is true. A checkfailswhen the condition being checked is false, causing an exception to be raised.

§11.5(9–25) defines the checks; for example,Index_Checkchecks the bounds of an array value against its index constraint. A failure of this check will causeConstraint_Errorto be raised.

§11.5

4 pragmaSuppress(identifier [, [On =>] name]);

8 A pragma Suppress gives permission to an implementation to omit the named check from the place of the pragma to the end of the innermost enclosing declarative region, or, if thepragmais given in apackage_specificationand includes aname, to the end of the scope of the named entity. If thepragmaincludes a name, the permission applies only to checks performed on the named entity, or, for a subtype, on objects and values of its type. Otherwise, the permission applies to all entities. If permission has been given to suppress a given check, the check is said to be