Tom R. Halfhill, Editor
Two Kinds Of Logic
It's amazing how a few simple commands in a program can make a machine seem to think and act intelligently. In last month's column ("IF-THEN Intelligence") we discussed how a computer, using conditional logic, can examine a piece of information and make a decision. That capability is what sets computers apart from all other machines, even other programmable machines such as player pianos and many programmable calculators.
The main command in BASIC for this kind of decision making is the IF-THEN statement, and we promised that this month's column would cover two similar commands, ON-GOTO and ON-GOSUB. With IF-THEN, ON-GOTO, and ON-GOSUB, your programs can make another kind of decision called conditional branching. That means the computer can pass control to different parts of your program.
But before we delve deeper into conditional branching, there's a simpler concept that should be digested first-unconditional branching. As the term suggests, it's the opposite of conditional branching, and it's not as flexible or as powerful. Still, it plays an important part in computer programming. Often, conditional and unconditional branching work hand in hand to create the impression of computer intelligence that you seek in your programs. Together, these statements let you determine the pathways of the computer's thought.
Pathways Of Logic
Computers always execute their instructions (the program) in a certain order. That order is determined by you, the programmer, when you write the program and assign line numbers to the instructions. It's like jotting down directions so friends can find their way to your home: Take the freeway to the East 9th Street exit, turn right on Chester Avenue, and turn left at the park onto East 12th Street. Obviously, the directions won't do much good if they're followed in the wrong sequence.
Sometimes you need to modify your directions with an IF-THEN statement: IF Chester Avenue is blocked off for repairs, THEN turn right on Euclid Avenue instead. By applying conditional logic, your friends can decide between the two alternate routes.
At other times, however, you need to change the order in which instructions should be followed for some reason. Often you want the computer to repeat a certain set of instructions. That's where unconditional branching comes in. It lets you build in a detour.
The GOTO Detour
Try entering the following program. (Note: This program requires Extended BASIC on the TI99/4A. Also, the TI-99/4A requires that you replace the colons in lines 30 and 40 with a pair of colons.)
10
PRINT "Enter a number from 1 to 10 and press
RETURN or ENTER."
20 INPUT A
30 IF A<1 THEN PRINT "Number too small":GOTO
10
40 IF A>10 THEN PRINT "Number too big":GOTO
10
50 PRINT "Thank you."
RETURN or ENTER."
20 INPUT A
30 IF A<1 THEN PRINT "Number too small":GOTO
10
40 IF A>10 THEN PRINT "Number too big":GOTO
10
50 PRINT "Thank you."
Now run the program and experiment by entering different numbers when the questionmark prompt appears on the screen. You'll find that if you enter a number from 1 to 10 as the program requests, the computer thanks you. Otherwise, the computer reports that your number is outside the allowable range and then asks you to enter another number. It never stops asking until you comply with its request (computers can be persistent).
Here's a line-by-line breakdown of how the program works:
Line 10 prints the program's request for a number between 1 and 10.
Line 20 is an INPUT statement (which we'll discuss in depth in a future column). Briefly, it prints a question mark on the screen as a prompt and waits for the user to enter a number. Then it stores the number in memory and assigns the variable A as a reference to that number. (If the user types something besides a number, it may cause an error message to appear.)
Line 30 is a multistatement line, with the two statements separated by the colon. The first statement uses conditional logic to evaluate the user's response. Remember, only if the logical comparison proves true will the second part of the statement be executed. So, if the number the user enters is less than 1, the comparison is true and the program prints "Number too small." Then the computer continues to the second statement in this line-the unconditional branch. It, too, is carried out only if the preceding comparison was true. Therefore, you could say its execution is conditional upon the previous statement, but the branch itself is unconditional. As long as A is less than 1, the program will always GOTO 10-return to line 10 and ask the question again.
Line 40 is just like line 30, except it checks to see if the user's response was too large instead of too small. If so, it returns to line 10 again.
Line 50 prints the thank-you message if the program "falls through" both IF-THEN statements-in other words, if neither IF-THEN comparison is found true because the user's response is between 1 and 10.
In a simple way, lines 30 and 40 demonstrate the synergism between conditional and unconditional statements. Notice how they work together to direct the pathways of the program's execution to achieve what we want. Study some BASIC listings in magazines and books and see how IF-THENs and GOTOs are frequently paired to steer the programs in various directions.
Eliminating IF-THENs
By now you can see why IF-THEN is probably the most powerful single statement in BASIC. Its ability to evaluate a piece of information and thereby change the flow of a program is what gives you control over the computer.
But it's easy to get carried away with IF-THEN. It's such a useful statement that your programs can quickly become bulging with IF-THENs, and like anything that's overweight, the programs will move a little slower as a result. If the program needs to run fast, you have a problem. You can't just put the program on a crash diet by removing some IF-THENs. Remember, IF-THENs are what gives your computer its intelligence; those are brain cells, not fat cells.
You could try trimming away other parts of the program, but it's those IF-THENs with all their comparisons that are really slowing things down.
In many cases, the solution is the ON-GOTO or ON-GOSUB statements. Let's see a typical example of how ON-GOTO can take the place of a whole pile of IF-THENs. Here's a program fragment (part of a much larger program) that shows how someone might design a menu of five choices:
10
PRINT "1. Create a new file."
20 PRINT "2. Load a previous file."
30 PRINT "3. Save a file."
40 PRINT "4. Erase a file."
50 PRINT "5. Edit a file."
60 PRINT "Enter the number of your choice and
press RETURN";
70 INPUT A
80 IF A=1 THEN GOTO 1000
90 IF A=2 THEN GOTO 2000
100 IF A=3 THEN GOTO 3000
110 IF A=4 THEN GOTO 4000
120 IF A=5 THEN GOTO 5000
20 PRINT "2. Load a previous file."
30 PRINT "3. Save a file."
40 PRINT "4. Erase a file."
50 PRINT "5. Edit a file."
60 PRINT "Enter the number of your choice and
press RETURN";
70 INPUT A
80 IF A=1 THEN GOTO 1000
90 IF A=2 THEN GOTO 2000
100 IF A=3 THEN GOTO 3000
110 IF A=4 THEN GOTO 4000
120 IF A=5 THEN GOTO 5000
(This fragment assumes that lines 1000, 2000, 3000, 4000, and 5000 lead to additional programming which performs the functions described by the menu choices.)
Notice the stack of five IF-THENs. Imagine if the menu had ten choices. Or 15. All those IF-THENs look repetitive and redundant, don't they?
Fortunately, ON-GOTO gives us a way to eliminate those excess statements. In effect, ON-GOTO is a combination of IF-THEN and GOTO. Here's the same program fragment written another way:
10
PRINT "1. Create a new file."
20 PRINT "2. Load a previous file."
30 PRINT "3. Save a file."
40 PRINT "4. Erase a file."
50 PRINT "5. Edit a file."
60 PRINT "Enter the number of your choice and
press RETURN";
70 INPUT A
80 ON A GOTO 1000,2000,3000,4000,5000
20 PRINT "2. Load a previous file."
30 PRINT "3. Save a file."
40 PRINT "4. Erase a file."
50 PRINT "5. Edit a file."
60 PRINT "Enter the number of your choice and
press RETURN";
70 INPUT A
80 ON A GOTO 1000,2000,3000,4000,5000
Impressive, eh? One ON-GOTO statement replaces five lines of IF-THENs. What's more, a larger menu of 10 or 15 choices could still be handled by a single ON-GOTO (up to the linelength limit of your computer's BASIC screen editor-see your manual). It's a very readable statement, too. If A equals 1, execution continues at the line number which is first on the list (line 1000). If A equals 2, execution continues at the line number which is second on the list (line 2000). And so on. If only you could trim extra bulk off yourself this easily.
Dummy Line Targets
ON-GOTO is useful for many applications in which a program must branch to several different places based on a single variable. But there's a catch. The line numbers in the ON-GOTO list must be sequential and must correspond to the variable that's being evaluated.
For instance, if for some reason the above menu choices were numbered 4 through 9 instead of 1 through 5, selecting the first choice (item No. 4) would cause the ON-GOTO statement to continue execution at line 4000, not line 1000. Selecting the third choice (item No. 6) would cause the program to stop with an error message, because there is no sixth line number in the ON-GOTO list. You have to make sure the list of line numbers in the ON-GOTO statement always corresponds to the variable you're testing. There have to be as many line numbers as the largest number which can result from the input.
Of course, who ever numbers a menu 4 through 9 instead of 1 through 5? Nobody, maybe, but there are other ways this can happen. A typical situation is with joystick input. On an Atari computer, for example, the STICK(x) function in BASIC doesn't return a value from 1 to 8-as you might expect it to do with an eightposition joystick-but instead a value from 5 to 14. (There's a logical reason for this, but we can't explain it now.)
Since joysticks are read differently on various types of computers, let's make the point by avoiding the joystick example and designing a menu that looks like this on the screen:
5. Create a new file.
6. Load a previous file.
8. Save a file.
9. Erase a file.
12. Edit a file. Enter the number of your choice and press RETURN
6. Load a previous file.
8. Save a file.
9. Erase a file.
12. Edit a file. Enter the number of your choice and press RETURN
Of course, it's absurd to design a menu that's numbered like this, but you never know when you're going to have a bad day.
Now, your first urge might be to evaluate the input by the old method:
10
PRINT "Enter the number of your choice and
press RETURN"
20 INPUT A
30 IF A=5 THEN GOTO 1000
40 IF A=6 THEN GOTO 2000
50 IF A=8 THEN GOTO 3000
60 IF A=9 THEN GOTO 4000
70 IF A=12 THEN GOTO 5000
press RETURN"
20 INPUT A
30 IF A=5 THEN GOTO 1000
40 IF A=6 THEN GOTO 2000
50 IF A=8 THEN GOTO 3000
60 IF A=9 THEN GOTO 4000
70 IF A=12 THEN GOTO 5000
(As before, lines 1000-5000 would contain additional programming to carry out the menu choices.)
Yuk-look at all those IF-THENs. It doesn't seem possible to replace them with ON-GOTO here, because the numbers don't fall into the neat range of 1 through 5.
But there is a way to use ON-GOTO. First, figure out which number returned is the lowest in the range. In this case, selecting menu choice 5 sets A equal to 5. All the other numbers are larger. Too bad the 5 isn't a 1, right? Well, let's make it a 1 by subtracting 4:
25
A=A-4
Now every number returned by the INPUT statement is reduced by 4, so menu choice 5 becomes a 1, choice 6 becomes a 2, choice 8 be comes a 4, choice 9 becomes a 5, and choice 12 becomes an 8. But there's still a problem because of gaps in the sequence of numbers; they still don't fall into a neat range of 1 to 5.
The solution is simple: Just insert dummy target lines in the ON-GOTO list-lines that don't do anything. Since they'll never be executed, they won't cause any errors. But they will fill out the ON-GOTO list so the other lines fall into the right positions:
10
PRINT "Enter the number of your choice and
press RETURN"
20 INPUT A 25 A=A-4
30 ON A GOTO 1000,2000,3000,4000,5000,6000,
7000,8000
1000 REM Create a new file
2000 REM Load a previous file
3000 REM Dummy line
4000 REM Save a file
5000 REM Erase a file
6000 REM Dummy line
7000 REM Dummy line
8000 REM Edit a file
press RETURN"
20 INPUT A 25 A=A-4
30 ON A GOTO 1000,2000,3000,4000,5000,6000,
7000,8000
1000 REM Create a new file
2000 REM Load a previous file
3000 REM Dummy line
4000 REM Save a file
5000 REM Erase a file
6000 REM Dummy line
7000 REM Dummy line
8000 REM Edit a file
Lines 3000, 6000, and 7000 will never be executed, because the INPUT statement never returns the values 7, 10, or 11, which are changed to 3, 6, and 7 after line 25 subtracts 4.
Of course, a user could trip up this program by selecting those numbers anyway, even though they aren't listed on the menu, but we'll show how to protect against invalid input in a future column. The point of this example is to show how odd patterns of numbers can be made to work with ON-GOTO. As an exercise, try designing menus with the choices numbered in unusual ways, and then find methods to convert those numbers into sequences for ON-GOTO. There's always a way to make them work.
ON-GOSUB is very much like ON-GOTO, but that discussion will have to be postponed until next month when we cover the general concept of subroutines. Together with IF-THEN and ON-GOTO, the GOSUB and ON-GOSUB statements can really make your programs efficient, versatile, and powerful.