User Tools

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
        PRINT "Empty element not found"
        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
          PRINT "Empty element not found"
        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
          PRINT "Empty element not found"
        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
          PRINT "Empty element not found"
        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
          PRINT "Empty element not found"
        ENDIF

I hope you can see that there are several ways of avoiding GOTO. Not all of them necessarily improve a program's structure, but there is invariably one that has all the advantages but none of the disadvantages of using GOTO.

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
how_20to_20avoid_20gotos.txt · Last modified: 2024/01/05 00:22 by 127.0.0.1