Jump anywhere
You are encouraged to solve this task according to the task description, using any language you may know.
This task is demonstrate a local jump and a global jump and the various other types of jumps that the language supports. For the purpose of this task, the jumps need not be used for a single purpose and you have the freedom to use these jumps for different purposes. You may also defer to more specific tasks, like Exceptions or Generator. This task provides a "grab bag" for several types of jumps. There are non-local jumps across function calls, or long jumps to anywhere within a program. Anywhere means not only to the tops of functions!
- Some languages can go to any global label in a program.
- Some languages can break multiple function calls, also known as unwinding the call stack.
- Some languages can save a continuation. The program can later continue from the same place. So you can jump anywhere, but only if you have a previous visit there (to save the continuation).
These jumps are not all alike. A simple goto never touches the call stack. A continuation saves the call stack, so you can continue a function call after it ends.
Use your language to demonstrate the various types of jumps that it supports. Because the possibilities vary by language, this task is not specific. You have the freedom to use these jumps for different purposes. You may also defer to more specific tasks, like Exceptions or Generator.
Contents |
[edit] Ada
procedure Goto_Test is
begin
Stuff;
goto The_Mother_Ship; -- You can do this if you really must!
Stuff;
if condition then
Stuff;
<<Jail>>
Stuff;
end if;
Stuff;
-- Ada does not permit any of the following
goto Jail;
goto The_Sewer;
goto The_Morgue;
Stuff;
case condition is
when Arm1 =>
Stuff;
goto The_Gutter; -- Cant do this either
Stuff;
when Arm2 =>
Stuff;
<<The_Gutter>>
Stuff;
<<The_Sewer>>
Stuff;
end case;
Stuff;
for I in Something'Range loop
Stuff;
<<The_Morgue>>
if You_Are_In_Trouble then
goto The_Mother_Ship;
-- This is the usual use of a goto.
end if;
Stuff;
end loop;
Stuff;
<<The_Mother_Ship>>
Stuff;
end Goto_Test;
[edit] AutoHotkey
; Define a function.
function()
{
MsgBox, Start
gosub jump
free:
MsgBox, Success
}
; Call the function.
function()
goto next
return
jump:
MsgBox, Suspended
return
next:
Loop, 3
{
gosub jump
}
return
/*
Output (in Message Box):
Start
Suspended
Success
Suspended
Suspended
Suspended
*/
[edit] BASIC
10 GOTO 100: REM jump to a specific line
20 RUN 200: REM start the program running from a specific line
Some versions of basic allow line labels to be used. Here we jump to a label:
GOTO mylabel
[edit] C
C has goto LABEL keyword.
if (x > 0) goto positive;
else goto negative;
positive:
printf("pos\n"); goto both;
negative:
printf("neg\n");
both:
...
The label must be literal, not computed at run time. This won't work:
goto (x > 0 ? positive : negative);You can
goto almost anywhere inside the same function, but can't go across function boundaries. It's sometimes used to break out of nested loops:for (i = 0; ...) {although you can (not that you should) jump into a loop, too:
for (j = 0; ...) {
if (condition_met) goto finish;
}
}
goto danger;
for (i = 0; i < 10; i++) {
danger: /* unless you jumped here with i set to a proper value */
printf("%d\n", i);
}
For unwrapping call stack and go back up to a caller, see longjmp example; more powerful, but more expensive and complicated, is POSIX ucontext.
[edit] D
Apart from exception handling, D has the break and continue statements that can jump to a label in the current scope. The goto statement can jump to any label inside the current function.
[edit] J
J allows control to be passed to any named verb at any time. When the verb completes, control returns to the caller, unless an unhandled exception was raised.
For example:
F=: verb define
smoutput 'Now we are in F'
G''
smoutput 'Now we are back in F'
)
G=: verb define
smoutput 'Now we are in G'
throw.
)
F''
Now we are in F
Now we are in G
[edit] Java
The closest thing that Java has to a "goto" is labelled loops:
loop1: while (x != 0) {
loop2: for (int i = 0; i < 10; i++) {
loop3: do {
//some calculations...
if (/*some condition*/) {
//this continue will skip the rest of the while loop code and start it over at the next iteration
continue loop1;
}
//more calculations skipped by the continue if it is executed
if (/*another condition*/) {
//this break will end the for loop and jump to its closing brace
break loop2;
}
} while (y < 10);
//loop2 calculations skipped if the break is executed
}
//loop1 calculations executed after loop2 is done or if the break is executed, skipped if the continue is executed
}
[edit] Lua
Lua 5.2 introduced a goto statement along with labels. It was somewhat controversially implemented instead of a continue keyword, but it is more flexible and supports other types of jumps as well. goto only supports statically-defined labels.
-- Forward jump
goto skip_print
print "won't print"
::skip_print::
-- Backward jump
::loop::
print "infinite loop"
goto loop
-- Labels follow the same scoping rules as local variables, but with no equivalent of upvalues
goto next
do
::next:: -- not visible to above goto
print "won't print"
end
::next:: -- goto actually jumps here
-- goto cannot jump into or out of a function
::outside::
function nope () goto outside end -- error: no visible label 'outside' for <goto> at line 2
goto inside
function nope () ::inside:: end -- error: no visible label 'inside' for <goto> at line 1
-- Convenient for breaking out of nested loops
for i = 1, 10 do
for j = 1, 10 do
for k = 1, 10 do
if i^2 + j^2 == k^2 then
print(("found: i=%d j=%d k=%d"):format(i, j, k))
goto exit
end
end
end
end
print "not found"
::exit::
[edit] Mathematica
Mathematica supports non-local jumps to a previous Catch[] (via Throw[]).
There is Goto[Label] function in Mathematica. This allows "jumps" to arbitrary locations within (the same or other) functions.
[edit] MBS
goto mylabel;
[edit] МК-61/52
БП XX
XX is any address.
[edit] MUMPS
You can go to any point in any routine in the same namespace. In some implementations, you can even go between namespaces. It's not recommended though.
Some interpreters will allow you jump between blocks of the same depth. Others will let you leave, but not enter, a block.
;Go to a label within the program file
Goto Label
;Go to a line below a label
Goto Label+lines
;Go to a different file
Goto ^Routine
;Go to a label within a different file
Goto Label^Routine
;and with offset
Goto Label+2^Routine
;
;The next two goto commands will both return error M45 in ANSI MUMPS.
NoNo
For
. Goto Out
Out Quit
Goto NoNo+2
[edit] PARI/GP
GP lacks gotos and continuations, but can break out of arbitrarily many nested loops with break(n) which can be used to simulate goto within a given function. It can also use local values or error to break out of several layers of function calls, if needed.
PARI inherits C's ability to goto or longjmp; the latter is used extensively in the library.
[edit] Perl
Perl's goto LABEL and goto EXPR are a little too powerful to be safe. Use only under extreme duress (actually, not even then). goto &SUB is esoteric but much more innocuous and can occasionally be handy.
sub outer {
print "In outer, calling inner:\n";
inner();
OUTER:
print "at label OUTER\n";
}
sub inner {
print "In inner\n";
goto SKIP; # goto same block level
print "This should be skipped\n";
SKIP:
print "at label SKIP\n";
goto OUTER; # goto whatever OUTER label there is on frame stack.
# if there isn't any, exception will be raised
print "Inner should never reach here\n";
}
sub disguise {
goto &outer; # a different type of goto, it replaces the stack frame
# with the outer() function's and pretend we called
# that function to begin with
print "Can't reach this statement\n";
}
print "Calling outer:\n";
outer();
print "\nCalling disguise:\n";
disguise();
print "\nCalling inner:\n";
inner(); # will die
[edit] PicoLisp
PicoLisp supports non-local jumps to a previously setup environment (see exceptions) via 'catch' and 'throw', or to some location in another coroutine with 'yield' (see generator).
'quit' is similar to 'throw', but doesn't require a corresponding 'catch', as it directly jumps to the error handler (where the program may catch that error again).
There is no 'go' or 'goto' function in PicoLisp, but it can be emulated with normal list processing functions. This allows "jumps" to arbitrary locations within (the same or other) functions. The following example implements a "loop":
(de foo (N)
(prinl "This is 'foo'")
(printsp N)
(or (=0 (dec 'N)) (run (cddr foo))) )
Test:
: (foo 7) This is 'foo' 7 6 5 4 3 2 1 -> 0
[edit] PL/SQL
PL/SQL supports both GOTOs and structured exception handling:
DECLARE
i number := 5;
divide_by_zero EXCEPTION;
PRAGMA exception_init(divide_by_zero, -20000);
BEGIN
DBMS_OUTPUT.put_line( 'startLoop' );
<<startLoop>>
BEGIN
if i = 0 then
raise divide_by_zero;
end if;
DBMS_OUTPUT.put_line( 100/i );
i := i - 1;
GOTO startLoop;
EXCEPTION
WHEN divide_by_zero THEN
DBMS_OUTPUT.put_line( 'Oops!' );
GOTO finally;
END;
<<endLoop>>
DBMS_OUTPUT.put_line( 'endLoop' );
<<finally>>
DBMS_OUTPUT.put_line( 'Finally' );
END;
/
- Output:
startLoop 20 25 33.33333333333333333333333333333333333333 50 100 Oops! Finally
[edit] Python
Python has both exceptions and generators but no unstructured goto ability.
The "goto" module was an April Fool's joke, published on 1st April 2004. Yes, it works, but it's a joke nevertheless. Please don't use it in real code! For those who like computer languages with a sense of humour it can be downloded here. Unlike many Python modules it is well documented and comes with many examples. My favorite:
# Example 2: Restarting a loop:
from goto import goto, label
label .start
for i in range(1, 4):
print i
if i == 2:
try:
output = message
except NameError:
print "Oops - forgot to define 'message'! Start again."
message = "Hello world"
goto .start
print output, "\n"
It goes the extra mile and adds a comefrom keyword. This should be used only if you are evil and proud of it. It is reported to have caused maintenance programmers to have so strongly believed themselves insane that it became so. They are now under strong medication in padded cells. Basically whenever the code passes a label it jumps to the comefrom point. For best results I advise writing the comefrom code as far as possible from the label and using no comments near the label.
[edit] Racket
Racket, being a descendant of Scheme, supports full continuations.
As a little example:
#lang racket
(define (never-divides-by-zero return)
(displayln "I'm here")
(return "Leaving")
(displayln "Never going to reach this")
(/ 1 0))
(call/cc never-divides-by-zero)
; outputs:
; I'm here
; "Leaving" (because that's what the function returns)
Here, return is the program continuation being passed to the function, when it is called, the string "Leaving" i the result of the function and the following code is never executed.
A much more complicated example done here Where we generate elements of a list one at a time:
#lang racket
;; [LISTOF X] -> ( -> X u 'you-fell-off-the-end-off-the-list)
(define (generate-one-element-at-a-time a-list)
;; (-> X u 'you-fell-off-the-end-off-the-list)
;; this is the actual generator, producing one item from a-list at a time
(define (generator)
(call/cc control-state))
;; [CONTINUATION X] -> EMPTY
;; hand the next item from a-list to "return" (or an end-of-list marker)'
(define (control-state return)
(for-each
(lambda (an-element-from-a-list)
(set! return ;; fixed
(call/cc
(lambda (resume-here)
(set! control-state resume-here)
(return an-element-from-a-list)))))
a-list)
(return 'you-fell-off-the-end-off-the-list))
;; time to return the generator
generator)
[edit] Retro
Retro allows the user to compile jumps to named functions.
: foo 19 jump: 1+ 21 ;
When executed, the stack will contain 20; control does not return to the foo function.
[edit] REXX
Note: some REXXes don't allow jumping into a DO loop, although the language specificiations appear to allow it, as long as the END or the DO loop isn't executed. The following used PC/REXX to illustrate this example.
/*REXX pgm demonstrates various jumps (GOTOs). In REXX, it's a SIGNAL. */
say 'starting...'
signal aJump
say 'this statement is never executed.'
aJump: say 'and here we are at aJump.'
do j=1 to 10
say 'j=' j
if j==7 then signal bJump
end /*j*/
bJump: say 'and here we are at bJump.'
signal cJump
say 'this statement is never executed.'
do k=1 to 10
say 'k=' k
cJump: say 'and here we are at cJump.'
exit
end /*k*/
- Output:
starting... and here we are at aJump. j= 1 j= 2 j= 3 j= 4 j= 5 j= 6 j= 7 and here we are at bJump. and here we are at cJump.
After a rather longwinded discussion on the subject I offer here my view: Whereas PL/I disallows the use of GOTO to jump to anywhere
Compiler Messages Message Line.File Message Description IBM1847I S 212.0 GOTO target is inside a (different) DO loop.
Rexx is very liberal as to the use of Signal.
As mentioned above some implementations may have restrictions on that.
This Signal jumps into a Do loop inside a Procedure:
i=13
signal label
say 'This is never executed'
sub: Procedure Expose i
Do i=1 To 10;
label:
Say 'label reached, i='i
Signal real_start
End
Return
real_start:
Without the 'Signal real_start' which leads us out of the control structure the program would end with a syntax error when encountering the End correponding to the Do.
I recommend to use Signal only for condition handling and 'global' jumps to labels that are not within some structured constructs such as Do...End An example:
/* REXX ***************************************************************
* 12.12.2012 Walter Pachl
**********************************************************************/
Signal On Syntax
Parse Upper Arg part
If part<>'' Then
Interpret 'Signal' part
Say 'Executing default part'
Signal eoj
a:Say 'executing part A'
Signal eoj
b:Say 'executing part B'
Signal eoj
Syntax:
Say 'argument must be a or b or omitted'
Exit
eoj: say 'here we could print statistics'
This can be useful when the different parts of the program span a few pages. Also a Signal eoj in order to Exit from any point in the program to some final activities can be useful.
[edit] Ruby
Ruby programs almost never use continuations. MRI copies the call stack when it saves or calls a continuation, so continuations are slow.
The next example abuses a continuation to solve FizzBuzz#Ruby. It is slower and more confusing than an ordinary loop.
require 'continuation' unless defined? Continuation
if a = callcc { |c| [c, 1] }
c, i = a
c[nil] if i > 100
case 0
when i % 3
print "Fizz"
case 0
when i % 5
print "Buzz"
end
when i % 5
print "Buzz"
else
print i
end
puts
c[c, i + 1]
end
This code uses the Continuation object c to jump to the top of the loop. For the first iteration, callcc creates c and returns [c, 1]. For later iterations, callcc returns [c, i + 1]. For the last iteration, callcc returns nil to break the loop.
[edit] Run BASIC
for i = 1 to 10
if i = 5 then goto [label5]
next i
end
[label5]
print i
while i < 10
if i = 6 then goto [label6]
i = i + 1
wend
end
[label6]
print i
if i = 6 then goto [finish]
print "Why am I here"
[finish]
print "done"
[edit] Tcl
Tcl has both exceptions and (from 8.6 onwards) generators/coroutines but no unstructured goto ability. However, the main case where it might be desired, coding a general state machine, can be handled through metaprogramming (as discussed at some length on the Tcler's Wiki) so the absence is not strongly felt in practice.