 BBC BASIC Programmers' Reference

Site Tools

how_20to_20avoid_20gotos

How to avoid GOTOs

by Richard Russell, November 2006, revised June 2007 and October 2011

BBC BASIC includes the GOTO statement, but GOTOs are generally considered to be a bad thing. I won't repeat the arguments for avoiding GOTOs here: they are well explained in the tutorial, on Wikipedia and elsewhere. Suffice it to say that they can result in code which is difficult to understand, difficult to maintain and more likely to have bugs.

Supporters of GOTO will point to code examples such as the following as justification for their use:

```        FOR i = 1 TO maxi
FOR j = 1 TO maxj
FOR k = 1 TO maxk
IF a(i,j,k)=0 THEN GOTO 100
NEXT k
NEXT j
NEXT i
END

100   PRINT "Empty element found at: "i,j,k```

What this code does is to scan through all the elements of a 3-dimensional array, looking for the first empty (zero) element. When found it doesn't bother to look any further, and terminates the search by jumping out with GOTO. If it ever finishes the search it means an empty element was never found.

Admittedly it is clear how the code works, and it is one of the more acceptable uses of GOTO, but it is still undesirable (for example it doesn't clear down the stack, and could eventually result in running out of memory). How might we rework the routine to avoid the use of GOTO? One way would be to replace the FOR…NEXT loops with REPEAT…UNTIL loops:

```        i = 0
REPEAT i += 1
j = 0
REPEAT j += 1
k = 0
REPEAT k += 1
UNTIL a(i,j,k)=0 OR k=maxk
UNTIL a(i,j,k)=0 OR j=maxj
UNTIL a(i,j,k)=0 OR i=maxi

IF a(i,j,k)=0 THEN
PRINT "Empty element found at: "i,j,k
ELSE
ENDIF```

This certainly avoids the GOTO, but is it as clear? And what about execution speed? A simple measurement demonstrates that this 'improved' version takes about 40% longer to run.

Perhaps we can stick with using FOR…NEXT loops but avoid the GOTO another way:

```        imt = 0 : jmt = 0 : kmt = 0
FOR i = 1 TO maxi
FOR j = 1 TO maxj
FOR k = 1 TO maxk
IF a(i,j,k)=0 THEN
imt = i  : jmt = j  : kmt = k
i = maxi : j = maxj : k = maxk
ENDIF
NEXT k
NEXT j
NEXT i

IF a(imt,jmt,kmt)=0 THEN
PRINT "Empty element found at: "imt,jmt,kmt
ELSE
ENDIF```

This relies on the ability to terminate a FOR…NEXT loop prematurely by setting its control variable to the limit value (all versions of BBC BASIC let you do that). Note that it is now necessary to copy the indices at which the empty element was found, but the execution speed is at least as good as the first version (it may be faster, because GOTO itself is quite slow).

Here is a radically different approach:

```        IF FNsearch(i,j,k) THEN
PRINT "Empty element found at: "i,j,k
ELSE
ENDIF
END

DEF FNsearch(RETURN i,RETURN j,RETURN k)
FOR i = 1 TO maxi
FOR j = 1 TO maxj
FOR k = 1 TO maxk
IF a(i,j,k)=0 THEN = TRUE
NEXT k
NEXT j
NEXT i
=FALSE```

This time we've moved most of the code into a user-defined function. Now we can exit from the loops without using a GOTO, simply by returning early from the function.

The code is easy to understand, it runs quickly, and by moving the search routine into a function (which can be placed out of harm's way at the end of the program) we also adhere to one of the other principles of modern software practice: encapsulation. The theory is that it is better to move self-contained functional modules out of the main code so they don't clutter it and can be separately maintained.

There are however a couple of problems with this code. Firstly, some versions of BBC BASIC won't let you jump out of a function without first 'unrolling' the FOR…NEXT loops (BBC BASIC for Windows will). Secondly some people think it is cheating, because it's effectively still jumping out of the loops - just not using GOTO to do so!

Finally, if you're using BBC BASIC for Windows version 5.60 or later, you can make use of the EXIT statement added in that version:

```        FOR i = 1 TO maxi
FOR j = 1 TO maxj
FOR k = 1 TO maxk
IF a(i,j,k)=0 THEN EXIT FOR i
NEXT k
NEXT j
NEXT i

IF i <= maxi THEN
PRINT "Empty element found at: "i,j,k
ELSE 