Flow-control structures: Difference between revisions
(Added Java goto example.) |
m (→goto: Clarified comments) |
||
Line 189: | Line 189: | ||
goto skip; |
goto skip; |
||
} |
} |
||
//this code is skipped |
//this code is skipped if the goto is executed |
||
someOtherMethod(anotherVariable); |
someOtherMethod(anotherVariable); |
||
crazyAlgorithm(); |
crazyAlgorithm(); |
Revision as of 18:16, 8 December 2007
You are encouraged to solve this task according to the task description, using any language you may know.
These are examples of control structures. You may also be interested in:
In this task, we document common flow-control structures. One common example of a flow-control structure is the goto
construct. Note that Conditional Structures and Loop Structures have their own articles.
Ada
goto
Top: Put_Line("Hello, World"); goto Top;
exit
Exit is used to break out of loops. Exit can be used with a label to break out of an inner loop to an outer loop and its enclosing outer loop
Outer: loop -- do something loop -- do something else exit Outer; -- exits both the inner and outer loops end loop; end loop;
C
goto
One common use of goto in C is to break out of nested loops.
int main() { int i,j; for (j=1; j<1000; j++) { for (i=0; i<j, i++) { if (exit_early()) goto out; /* etc. */ } } out: return 0; }
C++
goto
Compiler: GCC 3.3.4
#include <iostream> int main() { LOOP: std::cout << "Hello, World!\n"; goto LOOP; }
Note that "goto" may also be used in conjunction with other forms of branching.
Exceptions
Compiler: GCC 4.0.2
Exceptions are a way to give control back to a direct or indirect caller in case of an error.
#include <iostream> #include <ostream> void foo() { std::cout << "Going to throw an exception.\n"; throw 7; // almost any object can be thrown, including ints std::throw << "This output will never execute.\n"; } void bar() { std::cout << "Going to call foo().\n"; foo(); std::cout << "This will be skipped by the exception coming from foo.\n"; } void baz() { try // everything thrown from inside the following code block { // will be covered by the following catch clauses std::cout << "Going to call bar().\n"; bar(); std::cout << "This will be skipped by the exception coming from foo.\n"; } catch(...) // a simple catch-all, but doesn't give access to the thrown exception { std::cout << "An exception occured. I'll just throw it on.\n"; throw; // without an argument, the caught exception is re-thrown } std::cout << "This will not be executed due to the re-throw in the catch block\n"; } void foobar() { try { baz(); } catch(char const* s) { std::cout << "If foo had thrown a char const*, this code would be executed.\n"; std::cout << "In that case, the thrown char const* would read " << s << ".\n"; } catch(int i) { std::cout << "Caught an int, with value " << i << " (should be 7).\n"; std::cout << "Not rethrowing the int.\n"; } catch(...) { std::cout << "This catch-all doesn't get invoked because the catch(int) above\n" << "already took care of the exception (even if it had rethrown the\n" << "exception, this catch-all would not be invoked, because it's\n" << "only invoked for exceptions coming from the try block.\n"; } std::cout << "This will be executed, since the exception was handled above, and not rethrown.\n"; } int main() { try { foobar(); } catch(...) { std::cout << "The main function never sees the exception, because it's completely handled\n" << "inside foobar(). Thus this catch-all block never gets invoked.\n"; } }
Forth
CATCH-THROW
Forth does not have goto, but the standard does have an exception mechanism.
: checked-array CREATE ( size -- ) DUP , CELLS ALLOT DOES> ( i -- a+i ) 2DUP @ 0 SWAP WITHIN IF SWAP 1+ CELLS + ELSE 1 THROW THEN ; 8 checked-array myarray : safe-access ( i -- a[i] ) ['] myarray CATCH 1 = IF ." Out of bounds!" 0 THEN ;
IDL
goto
test: ..some code here goto, test
(This is almost never used)
on_error
on_error, test
(This resumes at the label test if an error is encountered)
on_ioerror
on_ioerror, test
(Same as on_error, but for EOFs and read-errors and such)
break
break
immediately terminates the innermost current loop (or if or case etc)
continue
continue
immediately starts the next iteration of the current innermost loop
Java
goto
Goto's are generally disliked, but they're still in the language so you can use them if you want.
public static void main(String[] args){ inputStuff(); if(someStaticVariable == someSpecialValue){ goto skip; } //this code is skipped if the goto is executed someOtherMethod(anotherVariable); crazyAlgorithm(); skip: //this code is never skipped finish(); System.out.println("YOU WIN!"); }
Perl
Interpreter: Perl 5.x
goto
Goto is typically looked down upon by most perl programmers
FORK: # some code goto FORK;
Pop11
quitloop
quitloop with argument exits from nested loops:
while condition1 do while condition2 do if condition3 then quitloop(2); endif; endwhile; endwhile;
above quitloop(2) exits from both loops.
goto
goto l transfers control to the label l. goto may be used to exit from nested loops:
while condition1 do while condition2 do if condition3 then goto l; endif; endwhile; endwhile; l:;
Another use is to implement finite state machines:
state1: DO_SOMETHING(); if condition1 then goto state1; elseif condition2 then goto state2; .... else goto stateN; endif; state2: .... ... ... stateN: ....
Pop11 goto is a nonlocal one, so "jump out" from a chain of procedure calls:
define outer(); define inner(n); if n = 0 then goto final; endif; inner(n - 1); enddefine; inner(5); final:; enddefine;
This is useful to exit early from succesful recursive search, and for exception handling.
go_on
go_on is a multiway jump
go_on expression to lab1, lab2, ..., labN else elselab ;
If expression has value K the above will jump to label labK, if expression is not an ingeger, or if it ouside range from 1 to N, then control passes to label elselab. The else part may be omitted (then out of range values of expression cause an exception).
There is a more structured variant of go_on:
go_on expression to lab :
lab 1 : statement1; lab 2 : statement2; ....
endgo_on;
where lab is a prefix choosen by the user.
return
return ends execution of current function. In simplest form it is just:
return;
but it is also possible to specify one or more return values:
return(val1, val2, val3);
chain
chain has effect of "tail call" but is not nececcarly in tail position More precisely inside proc1
chain proc2(x1, x2, x3);
finishes execution of proc1 and transfers control to the proc2 passing it x1, x2, and x3 as arguments. On return from proc2 control passes to caller of proc1.
Remark: Pop11 does not perform "tail call optimization", one has to explicitely use chain.
Python
# Flow Control Structures in Python (Exceptions) # Exceptions are handled by the following operators: # try, except, finally, break, and continue, etc. # See each case for details... import math def main(): # ***** Case 1 - Try, Except ***** # try: temp = 0/0 # 'except' catches any errors that may have been raised between the code of 'try' and 'except' except: print "An error occurred." # Output : "An error occurred" # ***** Case 2 - Try, Except ***** # try: temp = 0/0 # here, 'except' catches a specific type of error raised within the try block. except ZeroDivisionError: print "You've divided by zero!" # Output : "You've divided by zero!" # ***** Case 3 - Try, Except, Finally ***** # try: temp = 0/0 except: print "An error occurred." # here, 'finally' executes when the try - except block ends, regardless of whether an error was raised or not # useful in areas such as closing opened file streams in the try block whether they were successfully opened or not finally: print "End of 'try' block..." # Output : # An error occurred # End of 'try' block... # ***** Case 4 - Try, Except within a function ***** # def divisionbyzero(): # create a function that is sure to fail temp = 0/0 try: divisionbyzero() except ZeroDivisionError: print "You've divided by zero!" # Output : # You've divided by zero! # ***** Case 5 - Try, Except, Else ***** # try: temp = 1/1 # not a division by zero error except ZeroDivisionError: # so... it is not caught print "You've divided by zero." # here, 'else' executes when no exceptions are caught... else: print "No apparent error occurred." # Output : # No apparent error occurred. # ***** Case 6 - Try, Except, break, continue ***** # i = 0 while 1: # infinite loop try: temp2 = 0/i # will raise a ZeroDivisionError first. temp = math.sqrt(i) break # 'break' will break out of the while loop except ValueError: # print "Imaginary Number! Breaking out of loop" break # 'break' out of while loop except ZeroDivisionError: print "You've divided by zero. Decrementing i and continuing..." i-=1 # we decrement i. # we 'continue', everything within the try - except block will be executed again, # this time however, ZeroDivisionError would not be raised again. continue # Note that removing it, replacing it with 'pass' would perform the equivalent # see below for a better example # Output : # You've divided by zero. Decrementing i and continuing... # Imaginary Number! Breaking out of loop # ***** Case 7 - Creating your own custom exceptions, raise ***** # # Let's call our custom error "StupidError"; it inherits from the Exception class class StupidError(Exception): def __init__(self, value): # 'value' is a constructor argument self.value = value def __str__(self): return repr(self.value) # Try it out. try: raise StupidError("Segfault") # here, we manually 'raise' the error within the try block except StupidError, details: # 'details' is the StupidError object we create in the try block. print 'Something stupid occurred:', details.value # so we access the value we had stored for it... # Output : # Something stupid occurred: Segfault # ***** Case 8 - continue ***** # i = 101 for i in range(0,4): # loop 4 times print "I will always be seen." continue # continue goes back to the loop beginning for a new iteration. print "I'll never be seen." print "Loop done" # Output: # I will always be seen. # I will always be seen. # I will always be seen. # I will always be seen. # Loop done if(__name__ == "__main__"): main()
Tcl
exception
Tcl's catch command can be used to provide a basic exception-handling mechanism:
if {[catch { ... code that might give error ... } result]} { puts "Error was $result" } else { ... process $result ... }
custom control structures
A novel aspect of Tcl is that it's relatively easy to create new control structures (more detail at http://wiki.tcl.tk/685). Eg. defining a command to perform some operation for each line of an input file:
proc forfilelines {linevar filename code} { upvar $linevar line ; # connect local variable line to caller's variable set filechan [open $filename] while {[gets $filechan line] != -1} { uplevel 1 $code ; # Run supplied code in caller's scope } close $filechan }
Now use it to print the length of each line of file "mydata.txt":
forfilelines myline mydata.txt { puts [string length $myline] }