## Chapter 11 - Looping with FOR

Back in the '80s, I used to work as a programmer for a company that made weighing machines. One project I had was to design a program to load weights onto a series of scales and take readings. The test station was to test four scales in turn. A colleague had tried the task and failed because he developed the code for one machine and then tried to copy it four times. A BBC Model B had 32k of memory: his program wouldn't fit. He was completely unaware of the computer's ability to run the same code repeatedly using a FOR loop. Effectively, I rewrote the program so it did this:
 REM Scale test FOR Scale%=1 TO 4 REM load some weights REM get some readings REM print the results NEXT Scale% END
Line 2 is the start of the loop. It tells the computer to use a variable (Scale% in this case) to keep count of how many times a loop has run and stop it when it gets past a limit, in this instance 4. When the line is first encountered, Scale% is created and set to 1. Lines 3-5 are then run. When line 6 is executed, the program jumps back to line 2, increases Scale% by 1, compares it with the final value, sees that it is less and runs lines 3-5 again. On the last repeat, when Scale% is 4, the program increases Scale% by 1, sees it has exceeded the final value and jumps to line 7 where it carries on with the rest of the program.

That's quite a lot of functionality for 2 lines of code, but as you've probably guessed, it doesn't stop there. For a start, the counter variable can be used in the loop itself so the code knows where it's up to:

 REM Scale test FOR Scale%=1 TO 4 PRINT "Currently testing scale: ";Scale% REM load some weights REM get some readings REM print the results NEXT Scale% END
... or to make decisions:
 REM Scale test FOR Scale%=1 TO 4
 CASE Scale% OF WHEN 1 : PRINT "Testing first scale" WHEN 2 : PRINT "Testing second scale" WHEN 3 : PRINT "Testing third scale" WHEN 4 : PRINT "Testing fourth scale" ENDCASE
 REM load some weights REM get some readings REM print the results NEXT Scale% END
... or anything else you may need it for. Obviously, the counter has no validity outside the loop, so don't use it there.

The start and finish values can take any logical value:
 FOR Count%=-10 TO 10 PRINT Count% NEXT Count%
or they can be variables or expressions:
 FOR Count%=MinValue% TO MaxValue%-10 PRINT Count% NEXT Count%
Each counter will start at the first value and increase by one until it passes the second value. You, as a programmer, must be careful here. If the final value is less than the start value, BB4W won't complain but you might be puzzled as to why your loop isn't behaving. Different dialects of BASIC react differently to this situation. BBC BASIC will run the loop at least once whatever values you give it.

There may be times when you want the program to repeat loops in increments other than one. Here, a new keyword can be used to force this. The following code will print all the odd numbers up to 20.

 REM STEP demo FOR Count%=1 TO 20 STEP 2 PRINT Count% NEXT Count% END
The keyword STEP forces the increment to the value specified. Again, it can be any logical value or expression for the type of variable you are using.
 FOR I=1 TO 5 STEP 0.5 REM ...

It can also be negative:
 FOR I%=10 TO 1 STEP -1 REM ...
In this case, BASIC works out that it's going in reverse and instead of stopping when I% is greater than 1, which it would do instantly, it stops when I% is less than 1 - makes sense really.

As with any other construct, it is possible to nest one inside another:

 FOR I%=1 TO 5 FOR J%=1 TO 5 PRINT I%,J% NEXT J% NEXT I%
Here, the inner loop is executed 5 times for each time the outer loop runs. The inner loop has to be fully contained in the outer loop. Try swapping NEXT J% and NEXT I% and you will produce an error.

After all these variations on FOR, the other end of loop is not very exciting. NEXT is used as a placeholder to denote the end of the loop. The name of the count variable is not really needed as BASIC is clever enough to work out which NEXT ties up with which FOR. I prefer to put them in as it makes the code easier to read, especially if the loop covers more lines than can fit on the screen at one time.

In our nested example above, line 4 could have been replaced with:

 NEXT J%,I%
Try it, remove or REM line 5 first. The program will run as before doing 5 inner loops for each outer loop. BASIC will even accept:
 NEXT ,
Personally, I don't particularly like this method as it is not obvious where loops end and it messes up the indentation that the editor so neatly provides. That's just my preference though and you will see this used in other code.

Tip: Warnings with FOR loops
To end, I would like to mention several common errors that experience has taught:

a) Don't jump out of a loop using GOTO; if it's necessary, force the counter to a number above the final value and let it end naturally.

b) Please, please, please don't use conditional NEXTs. People condemn GOTO for encouraging bad programming practices, but it is possible to do bad things with any command. What I'm talking about is this sort of thing:
 REM ... program FOR I%=1 TO MaxNumber PRINT I%^2 IF I% MOD J%=0 THEN NEXT IF I%-1=J% NEXT ELSE J%=I%+1 : NEXT REM Rest of program ...
There are so many NEXTs here that the editor gets confused, and so will you. Always have only one NEXT for each FOR and give it a line to itself so the indentation allows you to clearly see where the loop starts and ends. You can always use block IFs to run code conditionally if required.

c) It's common amongst programmers of many languages to use I% and J% as counters. So much so that it is easy to forget and reuse the same counter deep within the code of another loop:
 FOR I%=1 TO 10 REM ... several pages of code ... FOR J%=1 TO 10 FOR I%=1 TO 99 REM Problem here using I% as we've REM just reset the first loop
You'll see what I mean one day because everyone does it, even though they've been warned!

Exercises

1) Write a program with a FOR loop to print the 5 times table. Each line should be in the format:

 1 * 5 = 5 2 * 5 = 10 ... 12 * 5 = 60
2) Use two nested FOR loops to draw a rectangle on the screen by using a line like PRINT TAB(X,Y);"*"