Computers: Universe: Basic Flow Control

Flow control

Usually, each statement in your program is executed in turn until the final END statement is reached. Any divergence from this 'flow' must be deliberately engineered, and you have already seen two ways in which this can be done: by making statements conditional (see Basic Conditions) and by looping (see Loops). UniVerse Basic provides two further statements which you can use to control the order in which your statements run:

The unconditional jump: GOTO

To use GOTO, you must add two lines to your program. The first is a 'label', which serves as a kind of place marker. It can be just a number at the beginning of a line, but usually some kind of descriptive name is chosen. A name must be followed by a colon, like this SKIP.MESSAGE:. The second is the GOTO itself, which must be followed by the label to which control should be transferred:

PRINT 'Invoice entry complete.'
IF VALUE # 0 THEN GOTO SKIP.MESSAGE
PRINT 'Error! Value is 0!'
SKIP.MESSAGE:
* Continue with program...

This will work, but it's poor code. It's difficult to think of uses of GOTO which aren't: almost any use of GOTO can be better written using loops and conditions. For example, the code above could have been written:

PRINT 'Invoice entry complete.'
IF VALUE = 0 THEN PRINT 'Error! Value is 0!'
* Continue with program...

I would not advise someone never to use a GOTO, because all such arbitrary prohibitions eventually fall foul of some very particular circumstance where the the thing prohibited is found to be the most efficient, readable, and natural way to solve a problem, but I would suggest that GOTO will be so favoured very rarely, and you should try applying a loop or condition before employing it. If these prove complicated to implement, it may even be a sign that the overall structure of your program could be confused and could benefit from a clearer structure.

Internal subroutines: GOSUB

GOSUB is similar to GOTO in that it transfers control to a label somewhere in your code. The difference is that UniVerse Basic makes a note in memory of the point at which the GOSUB appeared, and as soon as it encounters a RETURN statement, it transfers control back to the line following the GOSUB. The net effect is to allow you to create 'subroutines' which allow complex tasks to appear in your 'main logic' as a single GOSUB statement, while their detailed implementation is tucked away lower in the program. For instance, consider the following:

GOSUB SELECT.INVOICES
LOOP
   GOSUB GET.INVOICE.NUMBER
UNTIL NO.MORE.INVOICES
   GOSUB PROCESS.INVOICE
REPEAT
STOP 'Invoice processing complete'

* Select the invoices.

SELECT.INVOICES:
   * Code to select invoices
   RETURN

* etc.

The beauty of this code is that its overall structure is almost impossible to miss from the 'main' loop at the head of the program. Future maintenance programmers may therefore turn their attention to discrete routines which handle the individual tasks: which may themselves (if they are complex) be broken down into further routines.

Breaking an alogorithm into logically distinct functions is recommended by almost all coding gurus, and so I need not bang on about its advantages to long. In UniVerse Basic, this practise can take two forms: the use of 'internal' subroutines via GOSUB, or the use of 'external' or 'shared' subroutines accessed via CALL (see
Basic External Subroutines later). As a general rule, I would suggest using GOSUB when the subroutines are genuinely specific to the current program, and using external subroutines only when they might genuinely be of use to other programs too. It is true that internal subroutines are not as discrete as many structured programming advocates would like - they have, for instance, access to all the variables in the same source file - but it is as well not to clutter your shared routine libraries with lots of routines other programmers will find useless. If you're keen on using an external subroutine, think carefully about how the task you have in mind might be 'generalised' to make it genuinely useful outside your current program, write and share the generalised version, and then call this from your program. For instance, perhaps GOSUB SELECT.INVOICES could be replaced with CALL SELECT.FILE('INVOICES', CRITERIA).