[Ada Information Clearinghouse]

Ada '83 Quality and Style:

Guidelines for Professional Programmers

Copyright 1989, 1991,1992 Software Productivity Consortium, Inc., Herndon, Virginia.

CHAPTER 5: Programming Practices

5.5 Expressions

Properly coded expressions can enhance the readability and understandability of a program. Poorly coded expressions can turn a program into a maintainer's nightmare.

Language Ref Manual references: 4.4 Expressions

In this section...
5.5.1 Range Values
5.5.2 Array Attributes
5.5.3 Parenthetical Expressions
5.5.4 Positive Forms of Logic
5.5.5 Short Circuit Forms of the Logical Operators
5.5.6 Accuracy of Operations With Real Operands
Summary of Guidelines from this section


5.5.1 Range Values

guideline

example

type Temperature      is range All_Time_Low .. All_Time_High; 
type Weather_Stations is range            1 ..  Max_Stations;

Current_Temperature : Temperature := 60; 
Offset              : Temperature;

... 
for I in Weather_Stations loop 
   Offset := Current_Temperature - Temperature'First;
   
   ... 
end loop;

rationale

In the example above, it is better to use Weather_Stations in the for loop than to use Weather_Stations'First .. Weather_Stations'Last or 1 .. Max_Stations, because it is clearer, less error-prone, and less dependent on the definition of the type Weather_Stations. Similarly, it is better to use Temperature'First in the offset calculation than to use All_Time_Low, because the code will still be correct if the definition of the subtype Temperature is changed. This enhances program reliability.

caution

When you implicitly specify ranges and attributes like this, be careful that you use the correct type or subtype name. It is easy to refer to a very large range without realizing it. For example, given the declarations:
type    Large_Range is new Integer;
subtype Small_Range is Large_Range range 1 .. 10;

then the first declaration below works fine, but the second one is probably an accident and raises an exception on most machines because it is requesting a huge array (indexed from the smallest integer to the largest one):
Array_1 : array (Small_Range) of Integer; 
Array_2 : array (Large_Range) of Integer;

Language Ref Manual references: 3.3.2 Subtype Declarations, 3.5 Scalar Types, 3.6 Array Types, 5.5 Loop Statements, A Predefined Language Attributes


5.5.2 Array Attributes

guideline

example

subtype Name_String is String (1 .. Name_Length);

File_Path : Name_String := (others => ' ');

...

for I in File_Path'Range loop 
   ... 
end loop;

rationale

In the example above, it is better to use Name_String'Range in the for loop than to use Name_String_Size, Name_String'First .. Name_String'Last, or 1 .. 30, because it is clearer, less error-prone, and less dependent on the definitions of Name_String and Name_String_Size. If Name_String is changed to have a different index type, or if the bounds of the array are changed, this will still work correctly. This enhances program reliability.

Language Ref Manual references: 3.6 Array Types, 3.6.1 Index Constraints and Discrete Ranges, A Predefined Language Attributes


5.5.3 Parenthetical Expressions

guideline

example

(1.5 * X**2)/A - (6.5*X + 47.0)

2*I + 4*Y + 8*Z + C

rationale

The Ada rules of operator precedence are defined in Section 4.5 of Department of Defense (1983) and follow the same commonly accepted precedence of algebraic operators. The strong typing facility in Ada combined with the common precedence rules make many parentheses unnecessary. However, when an uncommon combination of operators occurs, it may be helpful to add parentheses even when the precedence rules apply. The expression,

5 + ((Y ** 3) mod 10)

is clearer, and equivalent to

5 + Y**3 mod 10

The rules of evaluation do specify left to right evaluation for operators with the same precedence level. However, it is the most commonly overlooked rule of evaluation when checking expressions for correctness.

Language Ref Manual references: 4.4 Expressions, 4.5 Operators and Expression Evaluation, 4.5.6 Highest Precedence Operators


5.5.4 Positive Forms of Logic

guideline

example

Use

if Operator_Missing then

rather than either

if not Operator_Found then

or

if not Operator_Missing then

rationale

Relational expressions can be more readable and understandable when stated in a positive form. As an aid in choosing the name, consider that the most frequently used branch in a conditional construct should be encountered first.

exception

There are cases in which the negative form is unavoidable. If the relational expression better reflects what is going on in the code, then inverting the test to adhere to this guideline is not recommended.

Language Ref Manual references: 2.3 Identifiers, 4.5.1 Logical Operators and Short-circuit Control Forms


5.5.5 Short Circuit Forms of the Logical Operators

guideline

example

Use

if Y /= 0 or else (X/Y) /= 10 then

or

if Y /= 0 then
if (X/Y) /= 10 then

rather than either

if Y /= 0 and (X/Y) /= 10 then

or to avoid Numeric_Error

if (X/Y) /= 10 then

Use

if Target /= null and then Target.Distance < Threshold then

rather than

if Target.Distance < Threshold then

to avoid referencing a field in a non-existent object.

rationale

The use of short-circuit control forms prevents a class of data-dependent errors or exceptions that can occur as a result of expression evaluation. The short-circuit forms guarantee an order of evaluation and an exit from the sequence of relational expressions as soon as the expression's result can be determined.

In the absence of short-circuit forms, Ada does not provide a guarantee of the order of expression evaluation, nor does the language guarantee that evaluation of a relational expression is abandoned when it becomes clear that it evaluates to False (for and) or True (for or).

note

If it is important that all parts of a given expression always be evaluated, the expression probably violates Guideline 4.1.3 which limits side-effects in functions.

Language Ref Manual references: 4.5.1 Logical Operators and Short-circuit Control Forms


5.5.6 Accuracy of Operations With Real Operands

guideline

example

Current_Temperature   : Temperature :=       0.0; 
Temperature_Increment : Temperature := 1.0 / 3.0; 
Maximum_Temperature   : constant    :=     100.0;

... 
loop

   ... 
   Current_Temperature := 
         Current_Temperature + Temperature_Increment;
         
   ... 
   exit when Current_Temperature >= Maximum_Temperature;
   
   ... 
end loop;

rationale

Fixed and floating point values, even if derived from similar expressions, may not be exactly equal. The imprecise, finite representations of real numbers in hardware always have round-off errors so that any variation in the construction path or history of two reals has the potential for resulting in different numbers, even when the paths or histories are mathematically equivalent.

The Ada definition of model intervals also means that the use of <= is more portable than either < or =.

note

Floating point arithmetic is treated in Guideline 7.2.8.

exceptions

If your application must test for an exact value of a real number (e.g., testing the precision of the arithmetic on a certain machine), then the = would have to be used. But never use = on real operands as a condition to exit a loop.

honey Language Ref Manual references: 3.5.6 Real Types, 4.5.2 Relational Operators and Membership Tests, 4.5.7 Accuracy of Operations with Real Operands


Back to document index