Transferring control within the same procedure with the GoSub, On...GoSub, and Return statements

The branching statements GoSub and On...GoSub are nonstandard programming techniques with limited usefulness. They enable running a group of statements by transferring control from any number of other locations within the same procedure. Functionally the statements behave as a subroutine, but they can't take arguments, don't establish a separate scope, and aren't available from other procedures or scripts. It is more common and useful to write the statements as an ordinary sub.

The syntax is:

GoSub label

On expression GoSub label [ , label ]...

Return

The statement GoSub label transfers control to the statement labeled label and executes statements beginning at label, continuing until one of the following occurs:

  • A Return statement is encountered.

    Control returns to the statement following the GoSub statement.

  • An End statement is encountered; or an Exit Function, Exit Sub, or Exit Property statement is encountered; or an End Function, End Sub, or End Property statement is encountered.

    Execution of the script ends (End statement), or execution of the enclosing procedure ends (one of the other statements).

The group of statements executed after the labeled statement and before the Return statement, including any other transfers of control, acts as a subroutine within the current procedure.

The statement On expression GoSub label, label, ... transfers control similarly to GoSub label, except that the target label is conditioned on the value of expression: control transfers to the first label if expression is 1, to the second label if expression is 2, and so on. (Any of these labels may be the same.) The Return statement returns control to the statement following On...GoSub.

The location of the GoSub statement in the procedure is unrelated to the location of a labeled statement that it transfers control to. The only requirement is that the GoSub and its target labeled statements must be in the same procedure. The actual flow of control is determined at run time.

Execution of a GoSub or an On...GoSub statement defines a point of return. Another GoSub or On...GoSub may be executed before a Return statement is executed. When a Return is executed, control returns to the most recently defined point of return. Then that point of return becomes undefined.

The Return statement doesn't return from the procedure. It is a run-time error to attempt to execute a Return statement when there is no currently available point of return within the procedure.

These statements differ from the GoTo and On...GoTo statements, which transfer control without establishing a point of return.

This example uses On...GoSub to run one or the other of two simple performance tests on pieces of the LotusScript® language. By typing 1 or 2 into an input box, the user chooses whether to time 1000 iterations of a Do loop, or to count the number of Yields executed within one second. Using On...GoSub, the script branches to run one test or the other. A single Print statement reports the result.

Sub RunPerfTest
   Dim directTempV As Variant, directTest As Integer, i As Integer
   Dim startTime As Single, measure As Single, idPace As String
   SpecTest: directTempV = InputBox$ _
     (|Type 1 for iteration time, or 2 for # of yields:|)
   If Not IsNumeric(directTempV) Then Exit Sub
   directTest% = CInt(directTempV)
   If directTest% < 1 Or directTest% > 2 Then _
     Beep : GoTo SpecTest
   i% = 0
   ' Branch on 1 or 2.
   On directTest% GoSub TimeCheck, ItersCheck
   ' Return here to print the performance-test result,
   ' and leave.
   Print idPace$ measure!
   Exit Sub
TimeCheck:
   startTime! = Timer()
   Do While i% <= 1000
      i% = i% + 1
   Loop
   measure! = Timer() - startTime!
   idPace$ = "Time in seconds for 1000 Do iterations: "
   Return
ItersCheck:
   startTime! = Timer()
   Do While Timer() < startTime! + 1
      Yield
      i% = i% + 1
   Loop
   measure! = i%
   idPace$ = "Number of Yields in 1 second: "
   Return
End Sub
Call RunPerfTest()