Expand/Shrink

Goto Statement

Branches unconditionally to a specified line within a routine.

To quote the comp.lang.c FAQ:
It has long been observed that unfettered use of goto quickly leads to unmaintainable spaghetti code.
However, a simple, unthinking ban on the goto statement does not necessarily lead immediately to beautiful programming:
an unstructured programmer is just as capable of constructing a Byzantine tangle without using goto.
Many programmers adopt a moderate stance: goto should usually be avoided, but is acceptable in a few well-constrained
situations, if necessary: as multi-level break statements, to coalesce common actions inside a switch statement, or
to centralize cleanup tasks in a function with several error returns.
Blindly avoiding certain constructs or following rules without understanding them can lead to just as many problems as
the rules were supposed to avert. Furthermore, many opinions on programming style are just that: opinions.
They may be strongly argued and strongly felt, they may be backed up by solid-seeming evidence and arguments, but the
opposing opinions may be just as strongly felt, supported, and argued. It is usually futile to get dragged into "style wars",
because on certain issues, opponents can never seem to agree, or agree to disagree, or stop arguing.

Situations in which goto is often useful include:
  • To make the code more readable and easier to follow
  • To make smaller programs, and get rid of code duplication
  • Implementing multi-level break and continue from nested loops and condition.
  • Error handling, and particularly cleanup code such as resource deallocation.
The first of those is several orders of magnitude more compelling than the last three combined together.
Imposing a self-policed rule that all jumps must be forward (or equivalently all backward, but never mixed) is recommended.

Phix imposes the following limitations on the use of goto statements:
A goto statement must be in the same function as the label it is referring.
The goto statement is not supported in top level code, outside of a routine definition.
There are no computed, assigned, or multiple target forms of the goto statement.
Goto may not be used and labels may not be defined anywhere inside a try/catch statement.
Jumping over variable initialisation will, naturally, leave the variable unassigned.
A goto can optionally refer to label or :label - they mean the same thing.
(Technically the colon-less variant is shorthand for the formal with-colon label reference.)
A label, which adheres to the usual identifier rules, is defined by preceding it with a double colon.

Example:
procedure p()
    goto label
    puts(1,"This will not be printed...\n")
::label
    puts(1,"...but this will\n")
end procedure
p()
Obviously a more meaningful name than label is strongly recommended, and anything like a 1970’s style L01 should be
cruelly and relentlessly mocked and ridiculed, unless the programmer is under six years old or recently suffered a stroke.

For hopefully obvious reasons goto rarely makes normal code faster and can actually make things bigger and slower:
        if condition then                       -- faster and smaller
            goto endif                          -- ==================
        else                                    if not condition then
            statements                              statements
        end if                                  end if
      ::endif
Besides, if the compiler did optimise away bizzare constructs such as that "then goto else", as in emit a single jmp instruction instead of the three consecutive jmp asked for, it would probably thwart some forms of trace and trapping in the debugger, or profiling, which might be the very reason for doing it like that in the first place.

Bear in mind that all the optimisations the compiler tries to make are based on standard structured programming constructs, and are disabled as soon as it encounters a low-level statement such as goto or inline assembly. For instance, after object o = 1 the compiler knows that o is an integer - toss in a goto and it has to say "right, I have no idea what o might be or even whether or not it is still unassigned".

pwa/p2js: JavaScript does not support the goto statement, and therefore neither does the transpiler.