Flow-control structures
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:
- Conditional structures
- Exceptions
- Flow-control structures
- Loops
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/categories.
[edit] 6502 Assembly
[edit] JMP
The jump instruction immediately jumps to any address:
JMP $8000 ;immediately JuMP to $8000 and begin executing
;instructions there.
The indirect jump instruction immediately jumps to the address contained in the address:
JMP ($8000) ;immediately JuMP to the address in memory locations
;$8000 and $8001
[edit] JSR
The jump to subroutine instruction pushes the address of the next instruction minus one onto the stack and jumps to any address:
JSR $8000 ;Jump to SubRoutine
A return from subroutine instruction pops the return address off the stack, adds one, and jumps to that location:
RTS ;ReTurn from Subroutine
[edit] BRK
A break instruction causes a non-maskable interrupt (setting the interrupt flag), pushes the current program counter address plus one onto the stack, pushes the flags onto the stack, then jumps to the address in the break vector (commonly at $FFFE and $FFFF):
BRK ;BReaK
The return from interrupt instruction pops the flags off the stack, pops the return address off the stack, adds one, and jumps to that location:
RTI ;ReTurn from Interrupt
[edit] Ada
[edit] goto
<<Top>>
Put_Line("Hello, World");
goto Top;
[edit] 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;
[edit] asynchronous transfer of control
A sequence of operation can be aborted with an asynchronous transfer of control to an alternative:
select
delay 10.0;
Put_Line ("Cannot finish this in 10s");
then abort
-- do some lengthy calculation
...
end select;
The alternative can be a delay statement or else an entry point call followed by a sequence of operations. The statement blocks at the delay or entry call and executes the sequence of the operation introduced by then abort. If blocking is lifted before completion of the sequence, the sequence is aborted and the control is transferred there.
[edit] ALGOL 68
See also Exceptions to see how ALGOL 68 handles transput events.
[edit] One common use of a label in ALGOL 68 is to break out of nested loops.
(
FOR j TO 1000 DO
FOR i TO j-1 DO
IF random > 0.999 THEN
printf(($"Exited when: i="g(0)", j="g(0)l$,i,j));
done
FI
# etc. #
OD
OD;
done: EMPTY
);
[edit] Multi way jump using labels and EXIT to return result
STRING medal = (
[]PROC VOID award = (gold,silver,bronze);
award[ 1 + ENTIER (random*3)];
gold: "Gold" EXIT
silver: "Silver" EXIT
bronze: "Bronze"
);
print(("Medal awarded: ",medal, new line));
[edit] Another use is to implement finite state machines
STRING final state = (
INT condition;
PROC do something = VOID: condition := 1 + ENTIER (3 * random);
state1:
do something;
CASE condition IN
state 1, state 2
OUT
state n
ESAC
EXIT
state 2:
"State Two"
EXIT
state n:
"State N"
);
print(("Final state: ",final state, new line));
[edit] ALGOL 68G implements a Refinement Preprocessor to aid with top down code development
# example from: http://www.xs4all.nl/~jmvdveer/algol.html - GPL #
determine first generation;
WHILE can represent next generation
DO calculate next generation;
print next generation
OD.
determine first generation:
INT previous := 1, current := 3.
can represent next generation:
current <= max int - previous.
calculate next generation:
INT new = current + previous;
previous := current;
current := new.
print next generation:
printf (($lz","3z","3z","2z-d$, current,
$xz","3z","3z","2z-d$, previous,
$xd.n(real width - 1)d$, current / previous)).
Sample output:
Exited when: i=13, j=53
Medal awarded: Gold
Final state: State Two
4 3 1.33333333333333
7 4 1.75000000000000
11 7 1.57142857142857
etc...
[edit] AutoHotkey
MsgBox, calling Label1
Gosub, Label1
MsgBox, Label1 subroutine finished
Goto Label2
MsgBox, calling Label2 ; this part is never reached
Return
Label1:
MsgBox, Label1
Return
Label2:
MsgBox, Label2 will not return to calling routine
Return
[edit] AWK
The [awk] programming language is data driven. However, Awk has break and continue for loop control, as in C.
$ awk 'BEGIN{for(i=1;;i++){if(i%2)continue; if(i>=10)break; print i}}'
2
4
6
8
[edit] BBC BASIC
BBC BASIC has GOSUB and GOTO but they are deprecated.
GOSUB subroutine
(loop)
PRINT "Infinite loop"
GOTO loop
END
(subroutine)
PRINT "In subroutine"
WAIT 100
RETURN
[edit] C
[edit] 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;
}
[edit] C++
[edit] goto
#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.
[edit] Exceptions
Exceptions are a way to give control back to a direct or indirect caller in case of an error. Note that throwing exceptions is usually very expensive, therefore they generally should only be used for exceptional situations.
#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";
}
}
[edit] D
[edit] goto
import std.stdio;
void main() {
label1:
writeln("I'm in your infinite loop.");
goto label1;
}
[edit] Exceptions
D supports the try/catch/finally mechanism:
import std.stdio;
class DerivedException : Exception {
this(string msg) { super(msg); }
}
void main(string[] args) {
try {
if (args[1] == "throw")
throw new Exception("message");
} catch (DerivedException ex) {
// We never threw a DerivedException, so this
// block is never called.
writefln("caught derived exception %s", ex);
} catch (Exception ex) {
writefln("caught exception: %s", ex);
} catch (Throwable ex) {
writefln("caught throwable: %s", ex);
} finally {
writeln("finished (exception or none).");
}
}
[edit] Scope guards
In a complex function, you might need to do cleanup in case of an exception, but it gets out of hand if there are many initialization steps that could fail. Scope guards offer a simplified syntax for try/finally.
There are three scopes you can listen for: exit, which is called unconditionally; failure, which is called if you leave the function via an exception; and success, which is called if you return from the function normally. A statement inside a scope block is only executed if execution reaches the scope block.
For instance:
import std.stdio;
void main(string[] args) {
scope(exit)
writeln("Gone");
if (args[1] == "throw")
throw new Exception("message");
scope(exit)
writeln("Gone, but we passed the first" ~
" chance to throw an exception.");
}
If the exception is thrown, then the only text that is written to the screen is "gone". If no exception is thrown, both calls to writeln occur.
scope(failure) and scope(success) work similarly.
[edit] E
E does not have goto. The only primitive flow control construct which is not a loop, conditional, or exception is escape, or ejectors.
The basic syntax is
escape ej {
...body...
}
Within body variable ej then contains a one-argument function (an ejector) which, if called, immediately returns the provided value from the escape block.
This is a limited form of continuation (it cannot be used after the escape block exits).
Loop break, loop continue, and return-from-middle-of-function are all defined in terms of this basic construct.
[edit] Forth
[edit] CATCH-THROW
Some Forth implementations have goto, but not the standard. It 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 ;
[edit] Go
Not covered here::
- Structures involving for, if, switch, continue, break, fallthrough, or panic. As mentioned in the task description, these structures are covered in other tasks.
- Short-circuit operators. These can be considered flow-control structures, but are also covered in other tasks.
- Flow-control functions in the standard library. Many of these are important, but covering them seems beyond the scope of the task.
[edit] Goto
Go has goto and labels. The following is an infinite loop:
func main() {
inf:
goto inf
}
[edit] Function call
Function call works as it does in most languages, transferring execution to to the called function, and returning execution to the following statement upon return from the called function.
The return statement returns from a function. Any function can use a return statement. Functions with return values can only return with a return statement. Functions without return values can return by “falling off” the end of the function.
The defer statement sets a function or method to be executed upon return from the enclosing function. This is useful when a function has multiple returns. The classic example is closing a file:
import "os"
func processFile() {
f, err := os.Open("file")
if err != nil {
// (probably do something with the error)
return // no need to close file, it didn't open
}
defer f.Close() // file is open. no matter what, close it on return
var lucky bool
// some processing
if (lucky) {
// f.Close() will get called here
return
}
// more processing
// f.Close() will get called here too
}
[edit] Goroutines
Goroutines are Go’s take on lightweight threads. A goroutine is started with a go statement, which looks like “go” preceding a function call. When the go statement executes, a new goroutine is created, execution in the new goroutine starts with a call to the function named in the go statement, and execution in the calling goroutine continues without interruption. (The main thread of execution is a goroutine itself.)
The following program prints a mix of 1’s and 0’s.
package main
import "fmt"
func printOnes() {
for {
fmt.Println("1")
}
}
func main() {
go printOnes()
for {
fmt.Println("0")
}
}
A goroutine terminates upon return from the function called in the go statement. Unlike with a regular function call however, it cannot return a value--the calling goroutine has long continued and there is nothing waiting for a return value.
Goroutines may not be able to communicate by returning values, but they have other ways. Principal is passing data through channels. Channel operations affect execution when they yield the processor, allowing other goroutines to run, but this does not normally alter flow of execution. The one exception is when channel operations are used in a select statement. A simple use,
func answer(phone1, phone2 chan int) {
select {
case <-phone1:
// talk on phone one
case <-phone2:
// talk on phone two
}
}
Syntax is strongly reminiscent of the switch statement, but rules for flow control are very different. Select will block if no channel operation is possible. If one is possible, it will execute that case. If multiple operations are possible, it will pick one at random.
[edit] Process initialization
A complete program must have exactly one function named main, which is called on program start up. In addition, a program can have any number of functions named init. These are called before main, but otherwise in unspecified order.
[edit] GW-BASIC
10 LET a=1
20 IF a=2 THEN PRINT "This is a conditional statement"
30 IF a=1 THEN GOTO 50: REM a conditional jump
40 PRINT "This statement will be skipped"
50 PRINT ("Hello" AND (1=2)): REM This does NOT PRINT
100 PRINT "Endless loop"
110 GOTO 100:REM an unconditional jump
[edit] Haskell
In the context of normal, functional-style code, there are no flow-control statements, because explicit flow control is imperative. A monad may offer flow control; what kinds are available depends on the monad. For example, the ExitT monad transformer lets you use the exitWith function to jump out a block of statements at will.
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Exit
main = do
runExitTMaybe $ do
forM_ [1..5] $ \x -> do
forM_ [1..5] $ \y -> do
lift $ print (x, y)
when (x == 3 && y == 2) $
exitWith ()
putStrLn "Done."
[edit] HicEst
More on HicEst's ALARM function
1 GOTO 2 ! branch to label
2 READ(FIle=name, IOStat=ios, ERror=3) something ! on error branch to label 3
3 ALARM(delay, n) ! n=2...9 simulate F2 to F9 keys: call asynchronously "Alarm"-SUBROUTINES F2...F9 with a delay
4 ALARM( 1 ) ! lets HicEst wait at this statement for any keyboard or mouse event
5 SYSTEM(WAIT=1000) ! msec
6 XEQ('CALL my_subroutine', *7) ! executes command string, on error branch to label 7
7 y = EXP(1E100, *8) ! on error branch to label 8
8 y = LOG( 0 , *9) ! on error branch to label 9
9 ALARM( 999 ) ! quit HicEst immediately
[edit] Icon and Unicon
Prelude about Goal-Directed Evaluation and Generators
Two of the key features of Icon and Unicon that affect program flow are Goal Directed Evaluation and Generators and Expression Failure. Goal Direction uses Generators to produce multiple results as needed and Expression Success and Failure forces the selection of logic pathways within programs.
goto
Does not exist in the Icon or Unicon language.
next
Restarts the enclosing loop. The conditional on the loop is evaluated as normal.
break expr
Default value of expr is the null value &null. This operator breaks out of the enclosing loop, yielding the expression as the result of the loop. Normally loops yield a failure ie no result, so you can write code like this:
if x := every i := 1 to *container do { # * is the 'length' operator
if container[i] ~== y then
write("item ", i, " is not interesting")
else
break a
} then
write("found item ", x)
else
write("did not find an item")
The expression given to break can be another break, which effectively lets you break out of two levels of loop. Finally, the expression given to break can be the next command; for example
break break next
breaks out of two levels of loop and re-enters the top of the third-level enclosing loop.
return expr
Default value of expr is &null. Apart from the usual meaning of return, if the expr value fails, then the procedure actually fails too, ie does not yield a value. See description of fail keyword. If the expr is capable of yielding more than one result, only the first result is asked for and used.
fail
Causes the the enclosing procedure to terminate without returning value. This is different from returning void or a null value that many other languages do when the code does not return an actual value. For example, in
x := ftn()
The value of x will not be replaced if ftn() issues the fail command. If ftn fails, then Goal-Directed Evaluation will also fail the assignment, therefore x is not assigned a new value. If the flow of control through a procedure falls off the end, the procedure implicitly fails.
suspend expr
Default value of expr is &null. Any procedure containing the suspend command will yield a value to the calling code. However the procedure remains in a state of suspended animation ready to be reactivated if the calling code demands another result due to Goal Directed Evaluation. Note that this capability is built directly into the runtime rather than being an artifically constructed behaviour provided by Python or C#'s use of the 'yield' keyword. Every and all expressions may suspend or be involved in a suspending expression without any effort. Behaviourally much closer to Prolog which also supports backtracking as a core part of the language. If the expr is capable of yielding more than one result, then supend (if driven) will progressively yield all of those values.
A procedure can contain several uses of suspend and it's quite reasonable for the procedure to execute many of them in any chosen order.
stop(expr)
Terminate program with prejudice.
error trapping
The keyword &error is normally zero, but if set to a positive value, this sets the number of fatal errors that are tolerated and converted to expression failure; the value of &error is decremented if this happens. Therefore the now-common TRY-CATCH behaviour can be written as:
&error := 1
mayErrorOut()
if &error == 1 then
&error := 0 # clear the trap
else {
# deal with the fault
handleError(&errornumber, &errortext, &errorvalue) # keyword values containing facts about the failure
}
Various idiomatic simplifications can be applied depending on your needs.
error throwing
Errors can be thrown using the function
runerr(errnumber, errorvalue) # choose an error number and supply the offending value
[edit] IDL
[edit] goto
test:
..some code here
goto, test
(This is almost never used)
[edit] on_error
on_error, test
(This resumes at the label test if an error is encountered)
[edit] on_ioerror
on_ioerror, test
(Same as on_error, but for EOFs and read-errors and such)
[edit] break
break
immediately terminates the innermost current loop (or if or case etc)
[edit] continue
continue
immediately starts the next iteration of the current innermost loop
[edit] J
Control structures should usually [but not always] be avoided in J. J's primitives already provide iteration and selection.
For example, here's an example of a program which loops over a sequence of integers, multiplying them by two (the result is displayed on the following line):
2 * 1 2 3
2 4 6
That said, J's control structures are documented at http://www.jsoftware.com/help/dictionary/ctrl.htm So, if you want to perform this same operation using a while loop, or a goto, you can do so. It's just... often not a good idea (but sometimes they are indispensable).
[edit] Java
"goto" is a reserved keyword in Java; but you cannot use it. There are currently no goto statements.
Java does provide two other statements that provide flow control: break and continue.
[edit] break
The break statement can be used to terminate a case clause in a switch statement and to terminate a for, while or do-while loop. In loops, a break can be labeled or unlabeled.
switch (xx) {
case 1:
case 2:
/* 1 & 2 both come here... */
...
break;
case 4:
/* 4 comes here... */
...
break;
case 5:
/* 5 comes here... */
...
break;
default:
/* everything else */
break;
}
for (int i = 0; i < 10; ++i) {
...
if (some_condition) { break; }
...
}
_Time_: do {
for (int i = 0; i < 10; ++i) {
...
if (some_condition) { break _Time_; /* terminate the do-while loop */}
...
}
...
} while (thisCondition);
[edit] continue
The continue statement skips the current iteration of a for, while, or do-while loop. As with break the continue statement can be labeled or unlabeled to allow iterating a loop level other than the current one in nested loops.
while (condition) {
...
if (someCondition) { continue; /* skip to beginning of this loop */ }
...
}
top: for (int 1 = 0; i < 10; ++i) {
...
middle: for (int j = 0; j < 10; ++j) {
...
bottom: for (int k = 0; k < 10; ++k) {
...
if (top_condition) { continue top; /* restart outer loop */ }
...
if (middle_condition) { continue middle; /* restart middle loop */ }
...
if (bottom_condition) { continue bottom; /* restart bottom loop */ }
...
if (bottom_condition) { continue; /* this will also restart bottom loop */ }
...
}
...
}
....
}
[edit] JavaScript
-
returnfrom a function ([1]) - loop control with
break [label]([2]) andcontinue [label]([3]) - exceptions with
throw([4]) andtry ... catch ... finally ...([5])
[edit] Lua
Lua has the break-command to exit loops.
i = 0
while true do
i = i + 1
if i > 10 then break end
end
[edit] Mathematica
Relevant functions are:
TimeConstrained[expr,t] evaluates expr, stopping after t seconds.
MemoryConstrained[expr,b] evaluates expr, stopping if more than b bytes of memory are requested.
Goto[tag] scans for Label[tag], and transfers control to that point.
CreateScheduledTask[expr,t] creates a task that will repeatedly evaluate expr every t second.
Interrupt[] interrupt a computation
Abort[] abort a computation
Quit[] immediately stops all execution and returns to the top level read-eval-print loop
Catch[] prepares for receiving a Throw[] while running a given list of executable expressions
Throw[] causes a non-local jump to a specified Catch[]
[edit] Maxima
/* goto */
block(..., label, ..., go(label), ...);
/* throw, which is like trapping errors, and can do non-local jumps to return a value */
catch(..., throw(value), ...);
/* error trapping */
errcatch(..., error("Bad luck!"), ...);
[edit] MUMPS
[edit] GOTO / G
The GOTO command jumps to a label. If the label is not in the current routine, it is necessary to include the circumflex and routine name.
GOTO LABEL^ROUTINE. This does not affect the subroutine stack, only the program pointer.
GOTO THERE
[edit] HALT / H
Halt and Hang have the same abbreviation, i.e. "H" but (as a mnemonic) Halt takes no arguments. Halt stops the current process, and clears all Locks and devices in Use. On the Cache variant of MUMPS, there is a $HALT special variable that can be set, the value of the $HALT special variable is a routine that is called before cleaning up (in effect, a specialized final error trap).
Read "Do you really wish to halt (Y/N)?",Q#1
IF Q="Y"!Q="y" HALT
[edit] JOB / J
The JOB command starts another MUMPS job starting at a label. If the label is not in the current routine, it is necessary to include the circumflex and routine name.
JOB LABEL^ROUTINE.
JOB THEREThis does not affect the subroutine stack, nor the program pointer in the current job. Since MUMPS is a multi-processing (rather than multi-threading) language, the new job is independent of the current job.
JOB LABEL^ROUTINE
[edit] QUIT / Q
Exits a loop, or routine. It decreases the stack level. It can return a value to a calling routine if there is a value after it.
Quit is one of the commands that requires two spaces after it if it is followed in a line by more commands.
FOR I=1:1:1 QUIT:NoLoop DO YesLoop
QUIT Returnvalue
[edit] XECUTE / X
eXecute acts as if it were a one line Do command. Its argument must be a string of valid MUMPS code, and it performs that code in a new stack level. There is an implied Quit at the end of each eXecute's argument string.
SET A="SET %=$INCREMENT(I)"
SET I=0
XECUTE A
WRITE I
The above block will output "1". Insertformulahere
[edit] Nemerle
Flow control statements made available in the Nemerle.Imperative namespace: break, continue, return (to return from somewhere other than the last expression in a function).
Exceptions can also be used to transfer control from a try block to a catch block.
[edit] NetRexx
NetRexx doesn't have a GOTO instruction and unlike Rexx the SIGNAL instruction is only used to throw exceptions.
Like Rexx however, NetRexx provides the LEAVE and ITERATE instructions.
[edit] LEAVE
The LEAVE instruction causes immediate exit from one or more DO, SELECT or LOOP constructs.
loop xx = 1 to 10
if xx = 1 then leave -- loop terminated by leave
say 'unreachable'
end
A name parameter can be provided to direct LEAVE to a specific end of block (as defined by a LABEL option or in the case of a controlled LOOP the control variable of the loop.
loop xx = 1 to 10 -- xx is the control variable
...
loop yy = 1 to 10 -- yy is the control variable
...
if yy = 3 then leave xx -- xx loop terminated by leave
if yy = 4 then leave yy -- yy loop terminated by leave
...
end
...
end xx
loop label xlabel xx = 1 to 10 -- xx is still the control variable but LABEL takes precidence
...
loop yy = 1 to 10 -- yy is the control variable
...
if yy = 3 then leave xlabel -- xx loop terminated by leave
...
end yy
...
end xlabel
do label FINIS
say 'in do block'
if (1 == 1) then leave FINIS
say 'unreachable'
signal Exception("Will never happen")
catch ex = Exception
ex.printStackTrace()
finally
say 'out of do block'
end FINIS
loop vv over ['A', 'B']
select label selecting case vv
when 'A' then do; say 'A selected'; say '...'; end
when 'B' then do;
say 'B selected';
if (1 == 1) then leave selecting;
say '...';
end
otherwise do; say 'nl selection'; say '...'; end
end selecting
end vv
[edit] ITERATE
The ITERATE instruction alters flow of control within a LOOP construct. On encountering an ITERATE instruction, execution of the loop body is terminated and control is passed directly back to the top of the loop just as though the last clause in the body of the loop had been executed.
As with LEAVE an optional name parameter can be supplied to direct the instruction to a loop level outside the current level.
loop fff = 0 to 9
...
loop xx = 1 to 3
...
if fff > 2 then iterate fff
...
end
...
end fff
[edit] OCaml
An OCaml user can simulate flow control using exceptions:
exception Found of int
let () =
(* search the first number in a list greater than 50 *)
try
let nums = [36; 23; 44; 51; 28; 63; 17] in
List.iter (fun v -> if v > 50 then raise(Found v)) nums;
print_endline "nothing found"
with Found res ->
Printf.printf "found %d\n" res
[edit] Oz
Exception handling is documented in other tasks: Exceptions#Oz, Exceptions Through Nested Calls#Oz.
The case statement can be used for Pattern Matching, but also like a switch statement in C:
case {OS.rand} mod 3
of 0 then {Foo}
[] 1 then {Bar}
[] 2 then {Buzz}
end
The Lisp-influenced for-loop is very powerful and convenient to use.
As a constraint programming language, Oz has a number of flow control structures which target logic programming. They are typically used to implement new constraint search engines. However, it is also possible to use them for general logic programming.
-
or: speculatively executes a number of alternative conditions and blocks until at most one alternative remains valid. Then either fails or commits to the remaining alternative if there is one.
-
cond: evaluates a number of conditions in parallel (or in undefined order) and commits to the first alternative that succeeds.
-
dis: depreciated
-
choice: creates a non-deterministic choice point. In other words, the statement provisionally chooses an alternatives. If the choice turns out to be wrong or if additional solutions to a puzzle are searched, another alternative is chosen.
As an example for choice, a simple, but stupid way to solve the equation 2*X=18. We assume that the solution is somewhere in the interval 8-10, but we do not quite know what exactly it is.
declare
proc {Stupid X}
choice
X = 8
{System.showInfo "choosing 8"}
[] X = 9
{System.showInfo "choosing 9"}
[] X = 10
{System.showInfo "choosing 10"}
end
2 * X = 18
end
in
{Show {SearchOne Stupid}}
Output:
choosing 8 choosing 9 [9]
[edit] PARI/GP
Flow control structures include function calling and returning, error/trap, next/break, alarm, and the various loops.
[edit] Pascal
[edit] goto
label
jumpto;
begin
...
jumpto:
some statement;
...
goto jumpto;
...
end;
[edit] exception
try
Z := DoDiv (X,Y);
except
on EDivException do Z := 0;
end;
[edit] Halt
Halt stops program execution and returns control to the calling program. The optional argument Errnum specifies an exit value. If omitted, zero is returned.
procedure halt(errnum: Byte);
[edit] Exit
Exit exits the current subroutine, and returns control to the calling routine. If invoked in the main program routine, exit stops the program. The optional argument X allows to specify a return value, in the case Exit is invoked in a function. The function result will then be equal to X.
procedure exit(const X: TAnyType)
Calls of functions/procedures as well as breaks and continues in loops are described in the corresponding tasks.
[edit] Perl
[edit] goto
Goto is typically looked down upon by most Perl programmers
FORK:
# some code
goto FORK;
[edit] Perl 6
[edit] Control exceptions
Control flow is extensible in Perl 6; most abnormal control flow (including the standard loop and switch exits) is managed by throwing control exceptions that are caught by the code implementing the construct in question. Warnings are also handled via control exceptions, and turn into control flow if the dynamic context chooses not to resume after the warning. See [S04/Control exceptions] for more information.
[edit] Phasers
Phasers are blocks that are transparent to the normal control flow but that are automatically called at an appropriate phase of compilation or execution. The current list of phasers may be found in [S04/Phasers].
[edit] goto
TOWN: goto TOWN;
Labels that have not been defined yet must be enclosed in quotes.
[edit] PHP
[edit] goto
Introduced in PHP 5.3, PHP now has a goto flow-control structure, even though most PHP programmers see it as a bad habbit (may cause spaghetti-code).
<?php
goto a;
echo 'Foo';
a:
echo 'Bar';
?>
Output:
Bar
[edit] PicoLisp
As this task asks for the documentation of common flow control structures, we refer here to the online documentation for more complete descriptions and examples.
Relevant functions are:
[edit] fork
fork creates a child process
[edit] task
task installs a background task consisting of an environment and a list of executable expressions
[edit] alarm
alarm schedules a timer, which runs a given list of executable expressions when it expires
[edit] abort
abort runs a given list of executable expressions, and aborts processing it if it takes longer than a given time
[edit] quit
quit immediately stops all execution and returns to the top level read-eval-print loop, optionally signaling an error
[edit] wait
wait delays current processing (optionally to a maximal time) until an optionally given condition evaluates to non-NIL
[edit] sync
sync synchronizes with other processes of the same family
[edit] protect
protect delays the processing of signals while a given list of executable expressions is executed
[edit] catch
catch prepares for receiving a 'throw' while running a given list of executable expressions
[edit] throw
throw causes a non-local jump to a specified 'catch' environment
[edit] bye
bye exits the interpreter
[edit] finally
finally specifies a list of executable expressions, to be run when current processing is done, even if a 'throw' or 'bye' was executed, or an error occurred.
[edit] PL/I
LEAVE
The LEAVE statement terminates execution of a loop.
Execution resumes at the next statement after the loop.
ITERATE
The ITERATE statement causes the next iteration of the loop to
commence. Any statements between ITERATE and the end of the loop
are not executed.
STOP
Terminates execution of either a task or the entire program.
SIGNAL FINISH
Terminates execution of a program in a nice way.
SIGNAL statement
SIGNAL <condition> raises the named condition. The condition may
be one of the hardware or software conditions such as OVERFLOW,
UNDERFLOW, ZERODIVIDE, SUBSCRIPTRANGE, STRINGRANGE, etc, or a
user-defined condition.
CALL
The CALL statement causes control to transfer to the named
subroutine.
SELECT
The SELECT statement permits the execution of just one of a
list of statements (or groups of statements).
It is sort of like a computed GOTO.
GO TO
The GO TO statement causes control to be transferred to the named
statement.
It can also be used to transfer control to any one of an array of
labelled statements. (This form is superseded by SELECT, above.)
[edit] Pop11
[edit] 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.
[edit] 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 successful recursive search, and for exception handling.
[edit] 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 integer, or if it outside 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 chosen by the user.
[edit] 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);
[edit] chain
chain has effect of "tail call" but is not necessarily 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 explicitly use chain.
[edit] PureBasic
[edit] Goto
Transfers control to the label referenced. It is not a safe way to exit loops.
If OpenConsole()
top:
i = i + 1
PrintN("Hello world.")
If i < 10
Goto top
EndIf
Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
Input()
CloseConsole()
EndIf
[edit] Gosub & Return
Gosub stands for 'Go to sub routine'. A label must be specified after Gosub where the program execution continues and will do so until encountering a Return. When a return is reached, the program execution is then transferred immediately below the Gosub. Gosub is useful when building fast structured code with very low overhead.
X=1: Y=2
Gosub Calc
;X will now equal 7
End
Calc:
X+3*Y
Return ; Returns to the point in the code where the Gosub jumped from
[edit] FakeReturn
If the command Goto is used within the body of a sub routine, FakeReturn must be used to correct the stack or the program will crash.
Gosub MySub
Lable2:
; The program will jump here, then 'end'
End
MySub:
If #PI>3
FakeReturn ; This will simulate the function of a normal "Return".
Goto Lable2
EndIf
Return
[edit] OnErrorGoto
This will transferee the program execution to the defined label if an error accrue.
OnErrorGoto(?MyExitHandler)
X=1: Y=0
z= X/Y
; = a illegal division with zero
Debug "This line should never be reached"
End
MyExitHandler:
MessageRequester("Error", ErrorMessage())
End
[edit] OnErrorCall
Similar to OnErrorGoto() but procedural instead.
Procedure MyErrorHandler()
;All open files etc can be closed here
MessageRequester("Error", ErrorMessage())
End
EndProcedure
OnErrorCall(MyErrorHandler())
X=1: Y=0
Z= X/Y
;This line should never be reached
[edit] Python
[edit] Loops
Python supports break and continue to exit from a loop early or short circuit the rest of a loop's body and "continue" on to the next loop iteration.
# Search for an odd factor of a using brute force:
for i in range(n):
if (n%2) == 0:
continue
if (n%i) == 0:
result = i
break
else:
result = None
print "No odd factors found"
In addition, as shown in the foregoing example, Python loops support an else: suite which can be used to handle cases when the loop was intended to search for something, where the code would break out of the loop upon finding its target. In that situation the else: suite can be used to handle the failure. (In most other languages one is forced to use a "sentinel value" or a special flag variable ... typically set to "False" before the loop and conditionally set to "True" within the loop to handle situations for which the Python else: on loops is intended).
[edit] Exceptions
A Python exception is simply any subclass of the built-in BaseException class, or any of its descendents. User defined exception classes are normally descendents of the Exception class (which is, itself, a subclass of BaseException). To "throw" any exception (user defined or otherwise) one uses the raise statement. To capture exceptions one must enclose the code in a try: ... except...: block. Any exception listed in an except block will catch all subclasses of that exception. For example ZeroDivisionError is derived from ArithmeticError. Thus an exception clause for ArithmeticError would catch a ZeroDivisionError (or any other ArithmeticError).
As a consequence of this one must arrange the order of exception clauses such that the more specific exceptions are listed (caught) before their more general base exceptions. Only the first matching exception clause will be executed. An except clause which lists no exceptions will catch all possible exceptions. (This is usually considered to be very poor programming practice because it can hide unintended coding errors).
An exception can be re-raised by simply calling the raise statement without any arguments (from within any exception handler). Thus a function can catch an exception, attempt to deal with it, then, if necessary, throw it it back to the next layer out in a given call stack. Uncaught exceptions will be handled by the interpreter by terminating the program and printing an error message and stack trace.
A custom Exception class is normally declared with the pass statement as no methods of the parent class are over-ridden, no additional functionality is defined and no attributes need be set. Example:
class MyException(Exception): pass
One normally would choose the most similar existing class. For example if MyException was going to be raised for some situation involving an invalid value it might be better to make it a subclass of ValueError; if it was somehow related to issues with inappropriate objects being passed around then one might make it a subclass of TypeError.
In large projects it's common to create an custom application base exception and to have all or most custom exceptions within that application or framework derive therefrom.
To create a "virtual base class" (one which is not intended to be directly instantiated, but exists solely to provide an inheritance to it's derived classes) one normally defines the requisite methods to raise "NotImplementedError" like so:
class MyVirtual(object):
def __init__(self):
raise NotImplementedError
It then becomes necessary for any descendants of this class to over-ride the __init__() method. Any attempt to instantiate a "MyVirtual" object directly will raise an exception.
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: # Note: catch all handler ... NOT RECOMMENDED
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...
Note: Prior to version 2.5 a try: statement could contain either series of except: clauses or a finally: clause but not both. It was thus necessary to nest the exception handling in an enclosing try:...finally: loop like so:
try:
try:
pass
except (MyException1, MyOtherException):
pass
except SomeOtherException:
finally:
do_some_cleanup() # run in any case, whether any exceptions were thrown or not
Case 4 - 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 5 - 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 6 - Creating your own custom exceptions, raise
# Let's call our custom error "StupidError"; it inherits from the Exception class
class StupidError(Exception): pass
# 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 # so we access the value we had stored for it...
# Output :
# Something stupid occurred: Segfault
[edit] continue, else in "for" loop
i = 101
for i in range(4): # loop 4 times
print "I will always be seen."
if i % 2 == 0:
continue # continue goes back to the loop beginning for a new iteration.
print "I'll only be seen every other time."
else:
print "Loop done"
# Output:
# I will always be seen.
# I will always be seen.
# I'll only be seen every other time.
# I will always be seen.
# I will always be seen.
# I'll only be seen every other time.
# Loop done
if(__name__ == "__main__"):
main()
[edit] The "with" statement
See [PEP 0343, The "with" statement]
class Quitting(Exception): pass
max = 10
with open("some_file") as myfile:
exit_counter = 0
for line in myfile:
exit_counter += 1
if exit_counter > max:
raise Quitting
print line,
The with statement allows classes to encapsulate "final" (clean-up) code which will automatically be executed regardless of exceptions that occur when working "with" these objects. Thus, for the foregoing example, the file will be closed regardless of whether it's more than 10 lines long. Many built-in and standard library classes have "context managers" which facilitate their use in with: code. In addition it's possible to define special __enter__() and __exit__() methods in one's own classes which will be implicitly called by the interpreter when an object is used within a with: statement.
Use cases for with: enabled objects include automated/guaranteed closing of files, release of threading lock objects, commit or rollback of database transactions, and save/restore of any desired state (such as terminal settings when using the curses module, the precision settings when using the Decimal module, or even saving and restoring sys.stdout for temporary redirection). It is a feature that seems to be unique to Python.
[edit] Yield expressions
See [PEP 0342, Coroutines via Enhanced Generators]
>>> value = 1 >>> echo = lambda: (yield value) >>> for i in echo(): ... print i ... 1
[edit] REBOL
rebol [
Title: "Flow Control"
Author: oofoe
Date: 2009-12-05
URL: http://rosettacode.org/wiki/Flow_Control_Structures
]
; return -- Return early from function (normally, functions return
; result of last evaluation).
hatefive: func [
"Prints value unless it's the number 5."
value "Value to print."
][
if value = 5 [return "I hate five!"]
print value
]
print "Function hatefive, with various values:"
hatefive 99
hatefive 13
hatefive 5
hatefive 3
; break -- Break out of current loop.
print [crlf "Loop to 10, but break out at five:"]
repeat i 10 [
if i = 5 [break]
print i
]
; catch/throw -- throw breaks out of a code block to enclosing catch.
print [crlf "Start to print two lines, but throw out after the first:"]
catch [
print "First"
throw "I'm done!"
print "Second"
]
; Using named catch blocks, you can select which catcher you want when throwing.
print [crlf "Throw from inner code block, caught by outer:"]
catch/name [
print "Outer catch block."
catch/name [
print "Inner catch block."
throw/name "I'm done!" 'Johnson
print "We never get here."
] 'Clemens
print "We never get here, either."
] 'Johnson
; try
div: func [
"Divide first number by second."
a b
/local r "Result"
][
if error? try [r: a / b] [r: "Error!"]
r ; Functions return last value evaluated.
]
print [crlf "Report error on bad division:"]
print div 10 4
print div 10 2
print div 10 1
print div 10 0
[edit] REXX
[edit] exit
The EXIT statement terminates the running (REXX) program and passes control to
the invoking program (it could be the shell/host/supervisor program).
If the invoking program is a REXX program, it also is terminated.
If an expression is coded, it normally is used to set the return code (also called
return code, completion code, or other such names).
Some operating systems require the expression to be a whole number (often with a
no expression or a [null] expression is usually taken to mean a return code of 0).
exit
exit expression
[edit] return
the RETURN statement terminates the running (REXX) program and passes control to
the invoking program (it could be the shell/host/supervisor program).
If the invoking program isn't a REXX program, the RETURN statement acts like an EXIT.
If the invoker is a REXX program and the RETURN statement has no EXPRESSION coded, and
the invoker expects a RESULT, a SYNTAX condition (error) is raised --- which usually
results in an abnormal termination of the invoking REXX program (this condition can be
trapped, however).
return
return expression
[edit] signal
The SIGNAL statement can be thought of as a GO TO statement, however, on issuance of
a SIGNAL statement, all executing DO loops and SELECTs are terminated.
Essentially, that means that there is no real way to re-enter a DO loop once a SIGNAL
statement is used.
Once a SIGNAL statement is executed, control passed to the first occurance of the label
specified (more than one label with the same name isn't considered an error).
The label can be any combination of letters, digits, periods, and some special symbols,
the most common are $, #, @, !, ?, and _ (underscore or underbar).
Some versions of REXX (CMS, TSO, R4) also allow the cent sign (¢).
The SIGNAL statement is also used to transfer control in case of some specific conditions:
∙ when an I/O stream (could be a file) isn't ready.
∙ when the REXX program used a variable that isn't defined.
∙ when a REXX syntax error occurs.
∙ when the program is HALTed (usually via a Ctrl─Alt─Del ──or── PA1 ──or── somesuch.
∙ when there is a loss of digits.
∙ when a command executed returns an error return code [other than 0 (zero)].
∙ when a command executed indicates a failure.
signal on error
signal on failure
signal on halt
signal on lostdigits
signal on notready
signal on novalue
signal on syntax
signal off error
signal off failure
signal off halt
signal off lostdigits
signal off notready
signal off novalue
signal off syntax
∙
∙
∙
signal on novalue
∙
∙
x=oopsay+1
∙
∙
∙
novalue: say
say '*** error! ***'
say
say 'undefined REXX variable' condition("D")
say
say 'in line' sigl
say
say 'REXX source statement is:'
say sourceline(sigl)
say
exit 13
∙
∙
∙
[edit] leave
The LEAVE statement transfer control to the next REXX statement following the END
statment of the current DO loop.
The LEAVE statement can also specify which DO loop is to be left if the DO loop has
a named variable.
do j=1 to 10
say 'j=' j
if j>5 then leave
say 'negative j=' -j
end
say 'end of the DO loop for j.'
∙
∙
∙
ouch=60
sum=0
do k=0 to 100 by 3
say 'k=' k
do m=1 to k
if m=ouch then leave k
sum=sum+m
end
end
say 'sum=' sum
[edit] iterate
The ITERATE statement immediately transfer control to the DO statement, that is, it iterates
(increments or decements) the named REXX variable that is specified on the DO statement.
The ITERATE statement can also specify which DO loop is to be iterated.
sum=0
do j=1 to 1000
if j//3==0 | j//7==0 then iterate
sum=sum+j
end
/*shows sum of 1k numbers except those divisible by 3 or 7.*/
say 'sum='sum
∙
∙
∙
numeric digits 5000
prod=0
do k=1 to 2000
do m=1 to k
if m>99 then iterate k
prod=prod*m
end
end
say 'prod=' prod
[edit] call
The CALL statement immediately transfer control to a named subroutine, and the CALL
statement may have any number (or none) parameters.
The named subroutine may or may not return a RESULT (which is similar to a return code).
numeric digits 1000 /*prepare for some gihugeic numbers.*/
∙
∙
∙
n=4
call factorial n
say n'!=' result
exit
factorial: parse arg x
!=1
do j=2 to x
!=!*j
end
return !
[edit] select
The SELECT statement is used to conditionaly test for cases to selectively execute REXX
statement(s).
∙
∙
∙
prod=1
a=7 /*or somesuch.*/
b=3 /* likewise. */
op='**' /*or whatever.*/
∙
∙
∙
select
when op=='+' then r=a+b /*add. */
when op=='-' then r=a-b /*subtract. */
when op=='*' then do; r=a*b; prod=prod*r; end /*multiply.*/
when op=='*' then r=a*b /*multiply. */
when op=='/' & b\=0 then r=a/b /*divide. */
when op=='%' & b\=0 then r=a/b /*interger divide. */
when op=='//' & b\=0 then r=a/b /*modulus (remainder). */
when op=='||' then r=a||b /*concatenation. */
when op=='caw' then r=xyz(a,b) /*call the XYZ subroutine*/
otherwise r='[n/a]' /*signify not applicable.*/
end
say 'result for' a op b "=" r
[edit] Ruby
[edit] return
Return from the currently executing method to the caller.
[edit] loop control
Ruby's loop control statements are: break, next, redo and retry. Break and next are obvious. Redo and retry both restart the current loop iteration, but retry first reevaluates the condition.
They can control while, until, for loops and iterators.
[edit] exceptions
Use raise to throw an exception. You catch exceptions in the rescue clause of a begin...end block.
begin
# some code that may raise an exception
rescue ExceptionClassA => a
# handle code
rescue ExceptionClassB, ExceptionClassC => b_or_c
# handle ...
rescue
# handle all other exceptions
else
# when no exception occurred, execute this code
ensure
# execute this code always
end
There is also a rescue modifier (example from the Pickaxe book):
values = ["1", "2.3", /pattern/]
result = values.map {|v| Integer(v) rescue Float(v) rescue String(v)}
# => [1, 2.3, "(?-mix:pattern)"]
[edit] catch and throw
break will only break out of a single level of loop. You can surround code in a catch block, and within the block you can throw a string or symbol to jump out to the end of the catch block (Ruby's GOTO, I suppose):
def some_method
# ...
if some_condition
throw :get_me_out_of_here
end
# ...
end
catch :get_me_out_of_here do
for ...
for ...
some_method
end
end
end
puts "continuing after catching the throw"
[edit] yield
yield passes control from the currently executing method to its code block.
[edit] SAS
/* GOTO: as in other languages
STOP: to stop current data step */
data _null_;
n=1;
p=1;
L1:
put n p;
n=n+1;
if n<=p then goto L1;
p=p+1;
n=1;
if p>10 then stop;
goto L1;
run;
/* LINK: equivalent of GOSUB in BASIC
RETURN: after a LINK, or to return to the beginning of data step */
data _null_;
input a b;
link gcd;
put a b gcd;
return;
gcd:
_a=a;
_b=b;
do while(_b>0);
_r=mod(_a,_b);
_a=_b;
_b=_r;
end;
gcd=_a;
return;
cards;
2 15
533 221
8 44
;
run;
[edit] Tcl
[edit] after
The after facility can be used to execute some code at some future time asynchronously, like this
after 1000 {myroutine x}
which will call "myroutine" with parameter "x" 1000ms from 'now'; no matter what other code might be running at the time (i.e. "after"; schedules the execution, then returns and continues program flow with the following code).
The scheduled task can be removed from the scheduler for example with
after cancel myroutine
(other ways are possible).
The correct way to schedule some regularly recurring task in TCL is to incorporate a self-scheduling at the end of the routine. For example the following will produce a clock whose display is updated once a second:
package require Tk
proc update {} {
.clockface configure -text [clock format [clock seconds]]
after 1000 update ; # call yourself in a second
}
# now just create the 'clockface' and call ;update' once:
pack [label .clockface]
update
[edit] loop control
Tcl has the break command to abort the current loop (for/foreach/while) and the continue command to skip to the next loop iteration.
[edit] 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 ...''
}
Tcl 8.6 also has a try…trap…finally structure for more complex exception handling.
try {
# Just a silly example...
set f [open $filename]
expr 1/0
string length [read $f]
} trap {ARITH DIVZERO} {} {
puts "divided by zero"
} finally {
close $f
}
[edit] 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). For example, this example defines 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 we can use it to print the length of each line of file "mydata.txt":
forfilelines myline mydata.txt {
puts [string length $myline]
}
[edit] Visual Basic .NET
[edit] Goto
This skips the line that changes the value of x to 5.
Sub bar2()
Dim x = 0
GoTo label
x = 5
label:
Console.WriteLine(x)
End Sub
[edit] On Error Goto
This brances in the event of an error. Usually there is an Exit (Sub|Function) to seperate the normal code from the error handling code
Sub foo()
On Error GoTo label
'do something dangerous
Exit Sub
label:
Console.WriteLine("Operation Failed")
End Sub
This style of code is rarely used.
[edit] On Error Resume Next
This performs a sequence of actions. If any action fails, the exception is discarded and next operation is performed.
Sub foo2()
On Error Resume Next
Operation1()
Operation2()
Operation3()
Operation4()
End Sub
This style of code is rarely used.
[edit] Return / Exit Sub
This shows the classical and modern syntax for exiting a sub routine early.
Sub Foo1()
If Not WorkNeeded() Then Exit Sub
DoWork()
End Sub
Sub Foo2()
If Not WorkNeeded() Then Return
DoWork()
End Sub
[edit] Return value / Exit Function
This shows the classical and modern syntax for exiting a function early. There is an implied variable with the same name as the function. This variable is write-only.
Function Foo3()
Foo3 = CalculateValue()
If Not MoreWorkNeeded() Then Exit Function
Foo3 = CalculateAnotherValue()
End Function
Function Foo4()
Dim result = CalculateValue()
If Not MoreWorkNeeded() Then Return result
Return CalculateAnotherValue()
End Function
- Programming Tasks
- Control Structures
- 6502 Assembly
- Ada
- ALGOL 68
- AutoHotkey
- AWK
- BBC BASIC
- C
- C++
- D
- E
- E examples needing attention
- Forth
- Go
- GW-BASIC
- Haskell
- HicEst
- Icon
- Unicon
- IDL
- J
- Java
- JavaScript
- Lua
- Mathematica
- Maxima
- MUMPS
- Nemerle
- NetRexx
- OCaml
- Oz
- PARI/GP
- Pascal
- Perl
- Perl 6
- PHP
- PicoLisp
- PL/I
- Pop11
- PureBasic
- Python
- REBOL
- REXX
- Ruby
- SAS
- Tcl
- Visual Basic .NET