Dealing with Faulty Logic
October 19, 2011 Ted Holt
Supposedly computer programming is a logical science. One would think, then, that computer programmers would be logical thinkers. It is not so. Let me provide a few examples of illogical thinking taken from real production programs. Then I will show a simple, low-tech way to deal with logical expressions so that they don’t end up illogical.
Let’s start with this example taken from fixed-format RPG specs. I suggest you find the bad logic yourself before reading my comments.
TYPE IFNE 'A' TYPE IFEQ 'S' XCODE CABNE 'S' CONTIN ENDIF TYPE IFEQ *BLANK XCODE CABEQ 'S' CONTIN ENDIF ENDIF
This code carries out the programmer’s intention. However, the first IF and its corresponding ENDIF are unnecessary.
Here’s another one.
PGM START: CALL PGM(PGM1) CALL PGM(PGM2) CLRPFM FILE(SOMELIB/SOMEFILE) GOTO END GOTO START END: ENDPGM
The second GOTO will never take place. Any unlabeled calculation that follows an unconditional branch will never run, and some language compilers flag such as an error. The CL compiler, however, doesn’t mind a bit, and won’t even generate a warning message.
Here’s a third example, before I move on to something more meaty.
If WarehouseType = 'C' Eval Balance = Quantity Else Eval Balance = Quantity Endif
It really doesn’t matter if the warehouse is controlled or uncontrolled, does it?
Now let’s look at a more complicated logic error.
If Balance > SkidQty and SkidQty > 1 and OrderType <> 'Z' or ShipmentType = '1' and SkidQty > 1 and OrderType <> 'Z' and Balance > SkidQty
This one is a bit more difficult to unravel, and most likely, the code does not carry out the programmer’s intentions.
Here’s an easy way to deal with complex conditions. You’ll need two high-tech implements–a pencil and a sheet of paper. You will use the pencil to draw a diagram of the logical expression on the paper.
First, here’s what an AND looks like:
And here’s what an OR looks like:
You can swap expressions within a single AND or OR. The following two expressions are identical.
As are these:
(There is one exception, however. If short-circuit evaluation applies, and an expression modifies a variable through a call to a subprocedure, then reordering the expressions may change the logic of the program. I prefer to avoid such logic, as it is unreliable and difficult to understand. See ShortCircuit Evaluation for more details.)
And you can mix ANDs and ORs, like this:
Before we diagram this expression, let’s reformat it to be sure we get it right. The system evaluates ANDs before ORs, so I add parentheses for clarification.
If (Balance > SkidQty and SkidQty > 1 and OrderType <> 'Z') or (ShipmentType = '01' and SkidQty > 1 and OrderType <> 'Z' and Balance > SkidQty)
Now, let’s diagram this expression:
Since some of the conditions are in both branches of the OR, let’s align them:
It’s clear that the value of ShipmentType is irrelevant. This complex condition is probably not accomplishing what the programmer intended.
Here are a few tips for dealing with complex conditions.
To expand on the last point, my experience is that comments tend to be worthless, and sometimes even misleading. Here is a worthless comment from a real production program.
This line prints when there are no errors and when there are errors.
I have no idea what the programmer was thinking.
A common misconception is that programming is equivalent to writing source code. Nothing could be further from the truth. Writing source code is only part of the programming process. A mistake people make (and one that I myself have made all too often) is to begin writing source code without first working out the solution to the problem at hand. The result is the type of code I’ve shown above.
Do what Thomas J. Watson, Sr., was urging IBM employees to do decades ago. Think.