Issues with ANDs and ORs (COBOL)

The first thing to note is that the code shown is the code which was working, and the amended code which did not give the desired result was never shown. As an addendum, why, if only one person were left, would more selection be necessary? To sum up that, the actual question is unclear beyond saying "I don't know how to use OR in COBOL. I don't know how to use AND in COBOL".

Beyond that, there were two actual questions:

  1. Did I make it too complex for the compiler?

  2. Is there an easier way to skip over things [is there a clearer way to write conditions]?

To the first, the answer is No. It is very far from difficult for the compiler. The compiler knows exactly how to handle any combinations of OR, AND (and NOT, which we will come to later). The problem is, can the human writer/reader code a condition successfully such that the compiler will know what they want, rather than just giving the result from the compiler following its rules (which don't account for multiple possible human interpretations of a line of code)?

The second question therefore becomes:

How do I write a complex condition which the compiler will understand in an identical way to my intention as author and in an identical way for any reader of the code with some experience of COBOL?

Firstly, a quick rearrangement of the (working) code in the question:

IF DL-CLASS-STANDING = 'First Yr' OR 'Second Yr'
AND GRAD-STAT-IN = ' ' OR 'X'

And of the suggested code in one of the answers:

IF (DL-CLASS-STANDING = 'First Yr' OR 'Second Yr')
AND (GRAD-STAT-IN = ' ' OR 'X')

The second version is clearer, but (or and) it is identical to the first. It did not make that code work, it allowed that code to continue to work.

The answer was addressing the resolution of the problem of a condition having its complexity increased: brackets/parenthesis (simply simplifying the complexity is another possibility, but without the non-working example it is difficult to make suggestions on).

The original code works, but when it needs to be more complex, the wheels start to fall off.

The suggested code works, but it does not (fully) resolve the problem of extending the complexity of the condition, because, in minor, it repeats the problem, within the parenthesis, of extending the complexity of the condition.

How is this so?

A simple condition:

IF A EQUAL TO "B"

A slightly more complex condition:

IF A EQUAL TO "B" OR "C"

A slight, but not complete, simplification of that:

IF (A EQUAL TO "B" OR "C")

If the condition has to become more complex, with an AND, it can be simple for the humans (the compiler does not care, it cannot be fooled):

IF (A EQUAL TO "B" OR "C")
AND (E EQUAL TO "F")

But what of this?

IF (A EQUAL TO "B" OR "C" AND E EQUAL TO "F")

Placing the AND inside the brackets has allowed the original problem for humans to be replicated. What does that mean, and how does it work?

One answer is this:

IF (A EQUAL TO ("B" OR "C") AND E EQUAL TO "F")

Perhaps clearer, but not to everyone, and again the original problem still exists, in the minor.

So:

IF A EQUAL TO "B"
OR A EQUAL TO "C"

Simplified, for the first part, but still that problem in the minor (just add AND ...), so:

IF (A EQUAL TO "B")
OR (A EQUAL TO "C")

Leading to:

IF ((A EQUAL TO "B")
OR (A EQUAL TO "C"))

And:

IF ((A EQUAL TO "B")
 OR (A EQUAL TO C))

Now, if someone wants to augment with AND, it is easy and clear. If done at the same level as one of the condition parts, it solely attaches to that. If done at the outermost level, it attaches to both (all).

IF (((A EQUAL TO "B")
  AND (E EQUAL TO "F"))
 OR (A EQUAL TO "C"))

or

IF (((A EQUAL TO "B")
 OR (A EQUAL TO "C"))
AND (E EQUAL TO "F"))

What if someone wants to insert the AND inside the brackets? Well, because inside the brackets it is simple, and people don't tend to do that. If what is inside the brackets is already complicated, it does tend to be added. It seems that something which is simple through being on its own tends not to be made complicated, whereas something which is already complicated (more than one thing, not on its own) tends to be made more complex without too much further thought.

COBOL is an old language. Many old programs written in COBOL are still running. Many COBOL programs have to be amended, or just read to understand something, and that many times over their lifetimes of many years.

When changing code, by adding something to a condition, it is best if the original parts of the condition do not need to be "disturbed". If complexity is left within brackets, it is more likely that code needs to be disturbed, which increases the amount of time in understanding (it is more complex) and changing (more care is needed, more testing necessary, because the code is disturbed).

Many old programs will be examples of bad practice. There is not much to do about that, except to be careful with them.

There isn't any excuse for writing new code which requires more maintenance and care in the future than is absolutely necessary.

Now, the above examples may be considered long-winded. It's COBOL, right? Lots of typing? But COBOL gives immense flexibility in data definitions. COBOL has, as part of that, the Level 88, the Condition Name.

Here are data definitions for part of the above:

01  A PIC X.
    88  PARCEL-IS-OUTSIZED VALUE "B" "C".
01  F PIC X.
    88  POSTAGE-IS-SUFFICIENT VALUE "F".

The condition becomes:

IF PARCEL-IS-OUTSIZED
AND POSTAGE-IS-SUFFICIENT

Instead of just literal values, all the relevant literal values now have a name, so that the coder can indicate what they actually mean, as well as the actual values which carry that meaning. If more categories should be added to PARCEL-IS-OUTSIZED, the VALUE clause on the 88-level is extended.

If another condition is to be combined, it is much more simple to do so.

Is this all true? Well, yes. Look at it this way.

COBOL operates on the results of a condition where coded.

If condition

Simple conditions can be compounded through the use of brackets, to make a condition:

If condition = If (condition) = If ((condition1) operator (condition2))...

And so on, to the limits of the compiler.

The human just has to deal with the condition they want for the purpose at hand. For general logic-flow, look at the If condition. For verification, look at the lowest detail. For a subset, look at the part of the condition relevant to the sub-set.

Use simple conditions. Make conditions simple through brackets/parentheses. Make complex conditions, where needed, by combining simple conditions. Use condition-names for comparisons to literal values.

OR and AND have been treated so far. NOT is often seen as something to treat warily:

IF NOT A EQUAL TO B
IF A NOT EQUAL TO B

IF (NOT (A EQUAL TO B)), remembering that this is just IF condition

So NOT is not scary, if it is made simple.

Throughout, I've been editing out spaces. Because the brackets are there, I like to make them in-your-face. I like to structure and indent conditions, to emphasize the meaning I have given them.

So:

IF ( ( ( condition1 )
    OR ( condition2 ) )
AND
     ( ( condition3 )
    OR ( condition4 ) ) )

(and more sculptured than that as well). By structuring, I hope that a) I mess up less and b) when/if I do mess up, someone has a better chance of noticing it.

If conditions are not simplified, then understanding the code is more difficult. Changing the code is more difficult. For people learning COBOL, keeping things simple is a long-term benefit to all.


As a rule, I avoid the use of AND if at all possible. Nested IF's work just as well, are easier to read, and with judicious use of 88-levels, do not have to go very deep. This seems so much easier to read, at least in my experience:

05  DL-CLASS-STANDING            PIC X(20) VALUE SPACE.
    88  DL-CLASS-STANDING-VALID  VALUE 'First Yr' 'Second Yr'.
05  GRAD-STAT-IN                 PIC X     VALUE SPACE.
    88  GRAD-STAT-IN-VALID       VALUE SPACE 'N'.

Then the code is as simple as this:

IF DL-CLASS-STANDING-VALID
    IF GRAD-STAT-IN-VALID
        ACTION ...  .

You may want to look into fully expanding that abbreviated expression since the expansion may not be what you think when there's a lot of clauses - it's often far better to be explicit.


However, what I would do is use the 88 level variables to make this more readable - these were special levels to allow conditions to be specified in the data division directly rather than using explicit conditions in the code.

In other words, put something like this in your data division:

03  DL-CLASS-STANDING  PIC X(20).
    88 FIRST-YEAR          VALUE 'First Yr'.
    88 SECOND-YEAR         VALUE 'Second Yr'.
03  GRAD-STAT-IN       PIC X.
    88 GS-UNKNOWN          VALUE ' '.
    88 GS-NO               VALUE 'X'.

Then you can use the 88 level variables in your expressions:

IF (FIRST-YEAR OR SECOND-YEAR) AND (GS-UNKNOWN OR GS-NO) ...

This is, in my opinion, more readable and the whole point of COBOL was to look like readable English, after all.


Try adding some parentheses to group things logically:

IF (DL-CLASS-STANDING = 'First Yr' OR 'Second Yr') AND (GRAD-STAT-IN = ' ' OR 'X')