Flow-control structures: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 323: Line 323:
print "No odd factors found"
print "No odd factors found"
</python>
</python>
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 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).

===Exceptions===
===Exceptions===
<pre>
# 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...


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).
import math

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.


def main():
</pre>
====Case 1 - Try, Except====
====Case 1 - Try, Except====
<pre>
<python>
try:
try:
temp = 0/0
temp = 0/0
# 'except' catches any errors that may have been raised between the code of 'try' and 'except'
# 'except' catches any errors that may have been raised between the code of 'try' and 'except'
except:
except: # Note: catch all handler ... NOT RECOMMENDED
print "An error occurred."
print "An error occurred."
# Output : "An error occurred"
# Output : "An error occurred"
</pre>
</python>
====Case 2 - Try, Except====
====Case 2 - Try, Except====
<pre>
<python>
try:
try:
temp = 0/0
temp = 0/0
Line 352: Line 350:
print "You've divided by zero!"
print "You've divided by zero!"
# Output : "You've divided by zero!"
# Output : "You've divided by zero!"
</pre>
</python>
====Case 3 - Try, Except, Finally====
====Case 3 - Try, Except, Finally====
<pre>
<python>
try:
try:
temp = 0/0
temp = 0/0
Line 366: Line 364:
# An error occurred
# An error occurred
# End of 'try' block...
# End of 'try' block...
</pre>
</python>

====Case 4 - Try, Except within a function====
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:
<pre>

def divisionbyzero(): # create a function that is sure to fail
<python>
temp = 0/0
try:
try:
divisionbyzero()
try:
pass
except ZeroDivisionError:
except (MyException1, MyOtherException):
print "You've divided by zero!"
# Output :
pass
except SomeOtherException:
# You've divided by zero!
finally:
</pre>
do_some_cleanup() # run in any case, whether any exceptions were thrown or not
====Case 5 - Try, Except, Else====
</python>
<pre>
====Case 4 - Try, Except, Else====
<python>
try:
try:
temp = 1/1 # not a division by zero error
temp = 1/1 # not a division by zero error
Line 389: Line 389:
# Output :
# Output :
# No apparent error occurred.
# No apparent error occurred.
</pre>
</python>
====Case 6 - Try, Except, break, continue====
====Case 5 - Try, Except, break, continue====
<pre>
<python>
i = 0
i = 0
while 1: # infinite loop
while 1: # infinite loop
Line 412: Line 412:
# You've divided by zero. Decrementing i and continuing...
# You've divided by zero. Decrementing i and continuing...
# Imaginary Number! Breaking out of loop
# Imaginary Number! Breaking out of loop
</pre>
</python>
====Case 7 - Creating your own custom exceptions, raise====
====Case 6 - Creating your own custom exceptions, raise====
<pre>
<python>
# Let's call our custom error "StupidError"; it inherits from the Exception class
# Let's call our custom error "StupidError"; it inherits from the Exception class
Line 428: Line 428:
# Output :
# Output :
# Something stupid occurred: Segfault
# Something stupid occurred: Segfault
</pre>
</python>


===Case 8 - continue, else in "for" loop===
===Case 7 - continue, else in "for" loop===
<pre>
<python>
i = 101
i = 101
for i in range(0,4): # loop 4 times
for i in range(4): # loop 4 times
print "I will always be seen."
print "I will always be seen."
if (i % 2) == 0:
continue # continue goes back to the loop beginning for a new iteration.
continue # continue goes back to the loop beginning for a new iteration.
print "I'll never be seen."
print "I'll only be seen every other time."
else:
else:
print "Loop done"
print "Loop done"
# Output:
# Output:
# I will always be seen.
# I will always be seen.
# 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 will always be seen.
# I will always be seen.
# I'll only be seen every other time.
# Loop done
# Loop done
if(__name__ == "__main__"):
if(__name__ == "__main__"):
main()
main()
</pre>
</python>


===The "with" statement===
===The "with" statement===
{{works with|Python|2.6}}
{{works with|Python|2.6}}
See [[http://www.python.org/peps/pep-0343.html PEP 0343, The "with" statement]]
See [[http://www.python.org/peps/pep-0343.html PEP 0343, The "with" statement]]

>>> with open("some_file"): # file ``some_file`` is closed after ``with`` block in any case whether an exception is raised or not
<python>
... raise Exception("an error")
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,
</python>

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.

===Yield expressions===
===Yield expressions===
{{works with|Python|2.5}}
{{works with|Python|2.5}}

Revision as of 18:31, 17 November 2008

Task
Flow-control structures
You are encouraged to solve this task according to the task description, using any language you may know.
Control Structures

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

Works with: GCC version 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

Works with: GCC version 4.0.2

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";
  }
}

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" is a reserved keyword in Java; but you cannot use it. There are currently no goto statements.

Perl

Works with: Perl version 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 successful 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 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.

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 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.

Python

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. <python>

  1. 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"

</python> 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).

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.

Case 1 - Try, Except

<python>

   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"    

</python>

Case 2 - Try, Except

<python>

   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!"

</python>

Case 3 - Try, Except, Finally

<python>

   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...

</python>

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:

<python>

  try:
      try:
          pass
      except (MyException1, MyOtherException):
          pass
      except SomeOtherException:
  finally:
      do_some_cleanup() # run in any case, whether any exceptions were thrown or not

</python>

Case 4 - Try, Except, Else

<python>

   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.

</python>

Case 5 - Try, Except, break, continue

<python>

   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

</python>

Case 6 - Creating your own custom exceptions, raise

<python>

   # 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

</python>

Case 7 - continue, else in "for" loop

<python>

   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()

</python>

The "with" statement

Works with: Python version 2.6

See [PEP 0343, The "with" statement]

<python>

  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,

</python>

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.

Yield expressions

Works with: Python version 2.5

See [PEP 0342, Coroutines via Enhanced Generators]

>>> value = 1
>>> echo = lambda: (yield value)
>>> for i in echo():
...   print i
...
1

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]
 }