Goto is a statement found in many computer programming languages. It performs a one-way transfer of control to another line of code; in contrast a Subroutine normally returns control. The jumped-to locations are usually identified using labels, though some languages use . At the machine code level, a goto is a form of branch or jump statement, in some cases combined with a stack adjustment. Many languages support the goto statement, and many do not (see § language support).
The structured program theorem proved that the goto statement is not necessary to write programs that can be expressed as ; some combination of the three programming constructs of sequence, selection/choice, and repetition/iteration are sufficient for any computation that can be performed by a Turing machine, with the caveat that code duplication and additional variables may need to be introduced.
The use of goto was formerly common, but since the advent of structured programming in the 1960s and 1970s, its use has declined significantly. It remains in use in certain common usage patterns, but alternatives are generally used if available. In the past, there was considerable debate in academia and industry on the merits of the use of goto statements. The primary criticism is that code that uses goto statements is harder to understand than alternative constructions. Debates over its (more limited) uses continue in academia and software industry circles.
The goto statement is often combined with the if statement to cause a conditional transfer of control.
'''IF''' ''condition'' '''THEN''' '''goto''' ''label''
Programming languages impose different restrictions with respect to the destination of a goto statement. For example, the C programming language does not permit a jump to a label contained within another function, however jumps within a single call chain are possible using the setjmp functions.
An alternative viewpoint is presented in Donald Knuth's Structured Programming with go to Statements, which analyzes many common programming tasks and finds that in some of them GOTO is the optimal language construct to use. In The C Programming Language, Brian Kernighan and Dennis Ritchie warn that goto is "infinitely abusable", but also suggest that it could be used for end-of-function error handlers and for multi-level breaks from loops. These two patterns can be found in numerous subsequent books on C by other authors;
a 2007 introductory textbook notes that the error handling pattern is a way to work around the "lack of built-in exception handling within the C language". Other programmers, including [[Linux]] kernel designer and coder [[Linus Torvalds]] or software engineer and book author [[Steve McConnell]], also object to Dijkstra's point of view, stating that GOTOs can be a useful language feature, improving program speed, size and code clarity, but only when used in a sensible way by a comparably sensible programmer. According to computer science professor [[John Regehr]], in 2013, there were about 100,000 instances of goto in the Linux kernel code.
Other academics took a more extreme viewpoint and argued that even instructions like break and return from the middle of loops are bad practice as they are not needed in the Böhm–Jacopini result, and thus advocated that loops should have a single exit point. For instance, Bertrand Meyer wrote in his 2009 textbook that instructions like break and continue "are just the old goto in sheep's clothing". A slightly modified form of the Böhm–Jacopini result, however, allows the avoidance of additional variables in structured programming, as long as multi-level breaks from loops are allowed. Because some languages like C don't allow multi-level breaks via their break keyword, some textbooks advise the programmer to use goto in such circumstances. The MISRA C 2004 standard bans goto, continue, as well as multiple return and break statements. The 2012 edition of the MISRA C standard downgraded the prohibition on goto from "required" to "advisory" status; the 2012 edition has an additional, mandatory rule that prohibits only backward, but not forward jumps with goto.
FORTRAN introduced structured programming constructs in 1978, and in successive revisions the relatively loose semantic rules governing the allowable use of goto were tightened; the "extended range" in which a programmer could use a GOTO to leave and re-enter a still-executing DO loop was removed from the language in 1978,ANSI X3.9-1978. American National Standard – Programming Language FORTRAN. American National Standards Institute. Also known as ISO 1539-1980, informally known as FORTRAN 77 and by 1995 several forms of Fortran GOTO, including the Computed GOTO and the Assigned GOTO, had been deleted.ISO/IEC 1539-1:1997. Information technology – Programming languages – Fortran – Part 1: Base language. Informally known as Fortran 95. There are a further two parts to this standard. Part 1 has been formally adopted by ANSI. Some widely used modern programming languages such as Java and Python lack the GOTO statement – see language support – though most provide some means of breaking out of a selection, or either Break statement out of or moving on to the next step of an iteration. The viewpoint that disturbing the control flow in code is undesirable may be seen in the design of some programming languages, for instance Ada visually emphasizes label definitions using angle brackets.
Entry 17.10 in comp.lang.c FAQ list addresses the issue of GOTO use directly, stating
Situations in which goto is often useful include:
These uses are relatively common in C, but much less common in C++ or other languages with higher-level features. However, throwing and catching an exception inside a function can be extraordinarily inefficient in some languages; a prime example is Objective-C, where a goto is a much faster alternative.
Another use of goto statements is to modify poorly factored legacy code, where avoiding a goto would require extensive refactoring or code duplication. For example, given a large function where only certain code is of interest, a goto statement allows one to jump to or from only the relevant code, without otherwise modifying the function. This usage is considered code smell, but finds occasional use.
Later, high-level languages such as Pascal were designed around support for structured programming, which generalized from (also known as procedures or functions) towards further control structures such as:
These new language mechanisms replaced equivalent flows which previously would have been written using gotos and ifs. Multi-way branching replaces the "computed goto" in which the instruction to jump to is determined dynamically (conditionally).
Under certain conditions it is possible to eliminate local goto statements of legacy programs by replacing them with multilevel loop exit statements.
Two solutions have been generally adopted: a way to exit a structured unit prematurely, and more generally exceptions – in both cases these go up the structure, returning control to enclosing blocks or functions, but do not jump to arbitrary code locations. These are analogous to the use of a return statement in non-terminal position – not strictly structured, due to early exit, but a mild relaxation of the strictures of structured programming. In C, Break statement and continue allow one to terminate a loop or continue to the next iteration, without requiring an extra while or if statement. In some languages multi-level breaks are also possible. For handling exceptional situations, specialized exception handling constructs were added, such as try/catch/finally in Java.
The throw-catch exception handling mechanisms can also be easily abused to create non-transparent control structures, just like goto can be abused.
Although Steele's paper did not introduce much that was new to computer science, at least as it was practised at MIT, it brought to light the scope for procedure call optimization, which made the modularity-promoting qualities of procedures into a more credible alternative to the then-common coding habits of large monolithic procedures with complex internal control structures and extensive state data. In particular, the tail call optimizations discussed by Steele turned the procedure into a credible way of implementing iteration through single tail recursion (tail recursion calling the same function). Further, tail call optimization allows mutual recursion of unbounded depth, assuming tail calls – this allows transfer of control, as in finite-state machines, which otherwise is generally accomplished with goto statements.
In Scheme, continuations can even move control from an outer context to an inner one if desired. This almost limitless control over what code is executed next makes complex control structures such as coroutines and cooperative multitasking relatively easy to write.
In versions prior to Fortran 95, Fortran also had an assigned goto variant that transfers control to a statement label (line number) which is stored in (assigned to) an integer variable. Jumping to an integer variable that had not been ASSIGNed to was unfortunately possible, and was a major source of bugs involving assigned gotos. The Fortran assign statement only allows a constant (existing) line number to be assigned to the integer variable. However, some compilers allowed accidentally treating this variable as an integer thereafter, for example increment it, resulting in unspecified behavior at goto time. The following code demonstrates the behavior of the goto i when line i is unspecified:
assign 200 to i
i = i+1
goto i ! unspecified behavior
200 write(*,*) "this is valid line number"
Several C compilers implement two non-standard C/C++ extensions relating to gotos originally introduced by gcc. The GNU extension allows the address of a label inside the current function to be obtained as a void* using the unary, prefix label value operator &&. The goto instruction is also extended to allow jumping to an arbitrary void* expression. This C extension is referred to as a computed goto in documentation of the C compilers that support it; its semantics are a superset of Fortran's assigned goto, because it allows arbitrary pointer expressions as the goto target, while Fortran's assigned goto doesn't allow arbitrary expressions as jump target. As with the standard goto in C, the GNU C extension allows the target of the computed goto to reside only in the current function. Attempting to jump outside the current function results in unspecified behavior.
Some variants of BASIC also support a computed GOTO in the sense used in GNU C, i.e. in which the target can be any line number, not just one from a list. For example, in MTS BASIC one could write GOTO i*1000 to jump to the line numbered 1000 times the value of a variable i (which might represent a selected menu option, for example).
PL/I label variables achieve the effect of computed or assigned GOTOs.
/* This implements the equivalent of */ /* the assigned goto */ declare where label; where = somewhere; goto where; ... somewhere: /* statement */ ; ...
A simpler way to get an equivalent result is using a label constant array that doesn't even need an explicit declaration of a LABEL type variable:/* This implements the equivalent of */ /* the computed goto */ declare where (5) label; declare inx fixed; where(1) = abc; where(2) = xyz; ... goto where(inx); ... abc: /* statement */ ; ... xyz: /* statement */ ; ...
/* This implements the equivalent of */ /* the computed goto */ declare inx fixed; ... goto where(inx); ... where(1): /* statement */ ; ... where(2): /* statement */ ; ...
FOR %%D in (Mon Wed Fri) do if "%%D" == "%D8dow%" goto SHOP%%D
echo Today, %D8dow%, is not a shopping day.
goto end
echo buy pizza for lunch - Monday is Pizza day.
goto end
echo buy Calzone to take home - today is Wednesday.
goto end
echo buy Seltzer in case somebody wants a zero calorie drink.
C# and Visual Basic .NET both support goto. However, it does not allow jumping to a label outside of the current scope, and respects object disposal and finally constructs, making it significantly less powerful and dangerous than the goto keyword in other programming languages. It also makes case and default statements labels, whose scope is the enclosing switch statement; goto case or goto default is often used as an explicit replacement for implicit fallthrough, which C# disallows.
The PL/I programing language has a GOTO statement that unwinds the stack for an out of block transfer and does not permit a transfer into a block from outside of it.
Other languages may have their own separate keywords for explicit fallthroughs, which can be considered a version of goto restricted to this specific purpose. For example, Go uses the fallthrough keyword and doesn't allow implicit fallthrough at all, while Perl 5 uses next for explicit fallthrough by default, but also allows setting implicit fallthrough as default behavior for a module.
Most languages that have goto statements call it that, but in the early days of computing, other names were used. For example, in MAD the TRANSFER TO statement was used. APL uses a right pointing arrow, → for goto.
C has goto, and it is commonly used in various idioms, as discussed above.
Functional programming languages such as Scheme generally do not have goto, instead using continuations.
|
|