79
Chapter 5 ■ Control StruCtureS: SeleCtion
To apply bracketing, you note that NOT takes precedence, so you write (NOT Num1 < 25). AND is next according to the precedence rules, so you bracket the ANDed conditions to give (Num2 = 80 AND Num3 > 264). Finally, the OR
is evaluated to give the full condition as
IF (NOT Num1 < 25) OR (Num2 = 80 AND Num3 > 264)THEN
DISPLAY "Done"
END-IF
Of course, you can use bracketing to change the order of evaluation. For instance, you can change the previous condition to
IF NOT (Num1 < 25 OR Num2 = 80) AND Num3 > 264 THEN
DISPLAY "Done"
END-IF
In the original condition, the order of evaluation was NOT..AND..OR, but the new bracketing changes that order to OR..NOT..AND. This change has a practical effect on the result of the condition.
Suppose all the simple conditions in the original expression are true. The truth table for that expression yields Table 5-4.
Table 5-4. IF Statement Evaluation When All the Simple Conditions Are True
Condition
IF(NOT Num1 < 25)
OR
(Num2 = 80
AND
Num3 > 264)
Expressed as
(NOT T)
OR
( T
AND
T )
Evaluates to
(F)
OR
( T
AND
T )
Evaluates to
(F)
OR
(T)
Evaluates to
True
The re-bracketed expression yields Table 5-5.
Table 5-5. The Rebracketed Truth Table
Condition
IF NOT
(Num1 < 25
OR
Num2 = 80)
AND
Num3 > 264
Expressed as
NOT
( T
OR
T )
AND
T
Evaluates to
NOT
(T)
AND
T
Evaluates to
(F)
AND
T
False
Implied Subjects
Although COBOL is often verbose, it does occasionally provide constructs that enable quite succinct statements to be written. The implied subject is one of those constructs.
80
Chapter 5 ■ Control StruCtureS: SeleCtion
When, in a complex condition, a number of comparisons have to be made against a single data item, it can be tedious to have to repeat the data item for each comparison. For instance, the example code fragment you saw earlier could be rewritten using implied subjects as
IF (ScrRow > 0 AND < 25) AND (ScrCol > 0 AND < 81) THEN
DISPLAY "On Screen"
END-IF
In this case, the implied subjects are ScrRow and ScrCol.
Similarly, using Grade = as the implied subject, you can rewrite
IF Grade = "A" OR Grade = "B" OR Grade = "C" THEN DISPLAY "Passed"
as
IF Grade = "A" OR "B" OR "C" THEN DISPLAY "Passed"
Finally, you can use the implied subject Num1 > to rewrite the expression
IF Num1 > Num2 AND Num1 > Num3 AND Num1 > Num4 THEN
DISPLAY "Num1 is the largest"
END-IF
as
IF Num1 > Num2 AND Num3 AND Num4
DISPLAY "Num1 is the largest"
END-IF
Nested IFs
COBOL allows nested IF statements (see Example 5-5). But be aware that although nested IF statements may be easy to write, they are somewhat difficult to understand when you return to them after an interval of time. Complex, and nested IF, statements are often used as a substitute for clear thinking. When you first attempt to solve a problem, you often don’t have a full understanding of it. As a result, your solution may be convoluted and unwieldy. It is often only after you have attempted to solve the problem that you gain sufficient insight to allow you to generate a simpler solution. When you have a better understanding of the problem, you may find that a mere reorganization of your code will greatly reduce both the number and complexity of the IF statements required. Simplicity is difficult to achieve but is a highly desirable objective. It is a principle of good program design that your solution should be only as complex as the problem demands.
Example 5-5. Nested IF..ELSE Statements
*> This example uses nested IF statements including IF..THEN..ELSE statements
*> This is quite a straight forward example of nested IFs but nested If & IF.. ELSE statements
*> can get a lot more convoluted and difficult to understand. It is especially difficult if
*> some nested IF statements do not have ELSE branches and others do. It can take some time
*> to untangle which ELSE belongs with which IF
81
Chapter 5 ■ Control StruCtureS: SeleCtion
IF InputVal IS NUMERIC
MOVE InputVal to Num1
IF Num1 > 5 AND < 25
IF Num1 < Num2
MOVE Num2 TO Num1
ELSE
MOVE Num1 TO Num2
END-IF
DISPLAY "Num1 & Num2 = " Num1 SPACE Num2
ELSE
DISPLAY "Num 1 not in range"
END-IF
ELSE
DISPLAY "Input was not numeric"
END-IF
Delimiting Scope: END-IF vs. Period
The scope of an IF statement may be delimited by either an END-IF or a period (full stop). For a variety of reasons, the explicit END-IF delimiter should always be used instead of a period. The period is so problematic that one of the most useful renovations you can perform on legacy COBOL code is to replace the periods with explicit scope delimiters.
There are two main problems with using a period as a scope delimiter. The first is that periods are hard to see, which makes it more difficult to understand the code. The second problem is that a period delimits all open scopes.
This is a source of many programming errors.
The code fragments in Example 5-6 illustrate the readability problem. Both IF statements are supposed to
perform the same task. But the scope of the IF statement on the left is delimited by an END-IF, whereas the statement on the right is delimited by a period.
Example 5-6. Comparing END-IF and Period-Delimited IF Statements
Statement1
Statement1
Statement2
Statement2
IF Num1 > Num2 THEN
IF Num1 > Num2 THEN
Statement3
Statement3
Statement4
Statement4
END-IF
Statement5
Statement5
Statement6.
Statement6.
Unfortunately, on the right, the programmer has forgotten to follow Statement4 with a delimiting period.
This means Statement5 and Statement6 will be included in the scope of the IF. They will be executed only if the condition is true. When periods are used to delimit the scope of an IF statement, this is an easy mistake to make; and, once made, it is difficult to spot. A period is small and unobtrusive compared to an END-IF.
The problem caused by unexpectedly delimiting scope is illustrated by the following code fragment:
IF Num1 < 10
ADD 10 TO Num1
MULTIPLY Num1 BY 1000 GIVING NUM2
ON SIZE ERROR DISPLAY "Error: Num2 too small".
DISPLAY "When is this shown?".
82
Chapter 5 ■ Control StruCtureS: SeleCtion
In this fragment, it looks as if the DISPLAY on the final line is executed only when Num1 is less than 10. However, a period has been used to delimit the scope of the ON SIZE ERROR (instead of an END-MULTIPLY delimiter)
, and that period also delimits the scope of the IF (all open scopes). This means the DISPLAY lies outside the scope of the IF and so is always executed.
If you replace the periods with explicit scope delimiters, you can see more clearly what is happening:
IF Num1 < 10
ADD 10 TO Num1
MULTIPLY Num1 BY 1000 GIVING NUM2
ON SIZE ERROR DISPLAY "Error: Num2 too small"
END-MULTIPLY
END-IF
DISPLAY "When is this shown?".
Even though the indentation used in this version is just as misleading as the period-based version, you are not misled. The explicit scope delimiters used for the IF and the MULTIPLY make the scope of these statements clear.
The use of delimiting periods in the PROCEDURE DIVISION is such a source of programming errors that a
minimum period style of programming has been advocated by Howard Tompkins1 and Robert Baldwin2. In the
examples in this book, I use a variation of the style suggested by Tompkins. Tompkins was writing before the 1985
standard was produced and so was not able to incorporate END delimiters into his scheme. Nowadays, you can adopt a style that uses only a single period per paragraph. Although Tompkins has persuasive arguments for placing that period alone on the line in column 12, for aesthetic reasons I use it to terminate the last statement in the paragraph.
Whether you prefer the Tompkins lonely period style or my variation, I strongly suggest that you adopt the minimum period style. That way you will save yourself a world of hurt.
Condition Names
Wherever a condition tests a variable for equality to a value, a set of values, or a range of values, that condition can be replaced by a kind of abstract condition called a condition name. Wherever it is legal to have a condition, it is legal have a condition name. Just like a condition, a condition name is either true or false.
Condition names allow you to give a meaningful name to a condition while hiding the implementation details of how the condition is detected. For instance,
IF CountryCode = 3 OR 7 OR 10 OR 15 THEN
MOVE 14 TO CurrencyCode
END-IF
may be replaced with
IF BritishCountry THEN
SET CurrencyIsPound TO TRUE
END-IF
This example illustrates the readability benefits of using condition names. When you encounter code such as IF CountryCode = 3 OR 7 OR 10 OR 15
the meaning of what the IF statement is testing is not obvious. You can see that CountryCode is being tested for particular values, but why? What is the significance of the values 3,7,10, and 15? What is the significance of moving 14
to the CurrencyCode? To discover this information, a maintenance programmer has to read external documentation or in-code comments. Now consider the condition name version of the IF statement. It is obvious what you are testing 83
Chapter 5 ■ Control StruCtureS: SeleCtion
because the test has been given a meaningful name. Similarly, the action taken when BritishCountry is true is also obvious. No documentation and no comments are required.
Ease of maintenance is also improved. If the coding system changed and the countries of the British Isles were now represented by the codes 4, 12, 18, and 25, only the definition of the condition name would have to be changed.
In the version that did not use the condition name, you would have to change the code values in all the places in the program where the condition was tested.
Defining Condition Names
Condition names are sometimes called level 88s because they are created in the DATA DIVISION using the special level number 88. The metalanguage for defining condition names is given in Figure 5-6.
Figure 5-6. Metalanguage for defining condition names
Rules
Condition names are always associated with a particular data item and are defined immediately after the definition of that data item. A condition name may be associated with a group data item and elementary data, or even the element of a table. The condition name is automatically set to true or false the moment the value of its associated data item changes.
When the VALUE clause is used with condition names, it does not assign a value. Instead, it identifies the value(s) which, if found in the associated data item, make the condition name true.
When identifying the condition values, a single value, a list of values, a range of values, or any combination of these may be specified. To specify a list of values, the entries are listed after the keyword VALUE. The list entries may be separated by commas or spaces but must terminate with a period.
Single Condition Name, Single Value
In Example 5-7, the condition name CityIsLimerick has been associated with CityCode so that if CityCode contains the value 2 (listed in the CityIsLimerick VALUE clause), the condition name will be automatically set to true.
Example 5-7. Defining and Using a Condition Name
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CityCode PIC 9 VALUE ZERO.
88 CityIsLimerick VALUE 2.
PROCEDURE DIVISION.
Begin.
: : : : : : : :
DISPLAY "Enter a city code (1-6) - " WITH NO ADVANCING
ACCEPT CityCode
84
Chapter 5 ■ Control StruCtureS: SeleCtion
IF CityIsLimerick
DISPLAY "Hey, we're home."
END-IF
: : : : : : : :
In the program fragment, DISPLAY and ACCEPT get a city code from the user. The instant the value in CityCode changes, the CityIsLimerick condition name will be set to true or false, depending on the value in CityCode.
Multiple Condition Names
Several condition names may be associated with a single data item. In Example 5-8, a number of condition names have been associated with CityCode. Each condition name is set to true when CityCode contains the value listed in the condition name VALUE clause. Condition names, like Booleans, can only take the value true or false. If a condition name is not set to true, it is set to false. Table 5-6 shows the Boolean value of each condition name for each value of CityCode.
Example 5-8. Associating Many Condition Names with a Data Item
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CityCode PIC 9 VALUE ZERO.
88 CityIsDublin VALUE 1.
88 CityIsLimerick VALUE 2.
88 CityIsCork VALUE 3.
88 CityIsGalway VALUE 4.
88 CityIsSligo VALUE 5.
88 CityIsWaterford VALUE 6.
PROCEDURE DIVISION.
Begin.
: : : : : : : :
DISPLAY "Enter a city code (1-6) - " WITH NO ADVANCING
ACCEPT CityCode
IF CityIsLimerick
DISPLAY "Hey, we're home."
END-IF
IF CityIsDublin
DISPLAY "Hey, we're in the capital."
END-IF
: : : : : : : :
Table 5-6. Results for Each Value of CityCode
Data Item / Condition Name
Data Value / Condition Name Result
CityCode
0
1
2
3
4
5
6
7–9
CityIsDublin
False
TRUE
False
False
False
False
False
False
CityIsLimerick
False
False
TRUE
False
False
False
False
False
CityIsCork
False
False
False
TRUE
False
False
False
False
CityIsGalway
r /> False
False
False
False
TRUE
False
False
False
CityIsSligo
False
False
False
False
False
TRUE
False
False
CityIsWaterford
False
False
False
False
False
False
TRUE
False
85
Chapter 5 ■ Control StruCtureS: SeleCtion
Overlapping and Multiple-Value Condition Names
When multiple condition names are associated with a single data item, more than one condition name can be
true at the same time. In Listing 5-2, UniversityCity is true if CityCode contains any value between 1 and 4.
These values overlap the values of the first four condition names, so if UniversityCity is true, then one of those four must also be true.
Listing 5-2. Multiple Condition Names with Overlapping Values
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing5-2.
AUTHOR. Michael Coughlan.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 CityCode PIC 9 VALUE ZERO.
88 CityIsDublin VALUE 1.
88 CityIsLimerick VALUE 2.
88 CityIsCork VALUE 3.
88 CityIsGalway VALUE 4.
88 CityIsSligo VALUE 5.
88 CityIsWaterford VALUE 6.
88 UniversityCity VALUE 1 THRU 4.
88 CityCodeNotValid VALUE 0, 7, 8, 9.
PROCEDURE DIVISION.
Begin.
DISPLAY "Enter a city code (1-6) - " WITH NO ADVANCING
ACCEPT CityCode
IF CityCodeNotValid
DISPLAY "Invalid city code entered"
ELSE
IF CityIsLimerick
DISPLAY "Hey, we're home."
END-IF
IF CityIsDublin
DISPLAY "Hey, we're in the capital."
END-IF
IF UniversityCity
DISPLAY "Apply the rent surcharge!"
END-IF
END-IF
STOP RUN.
The list of values that follows a condition name may be a single value, a number of values, or a range of values, or any mixture of these. When a range is specified, the word THROUGH or THRU is used to separate the minimum and maximum values in the range. In Listing 5-2, UniversityCity is true if CityCode contains any value between 1 and 4, whereas CityCodeNotValid is true if CityCode contains a value of 0 or 7 or 8 or 9. In Listing 5-2 I have chosen to list the individual values for CityCodeNotValid, but the value list could have been written as:
Michael Coughlan Page 13