Handling Errors

What will we cover?
  • 2 ways of dealing with errors
  • raising errors in our code for others to catch
  • The Traditional Way

    Traditionally when programmers do something, call a function say, the result of the function can be tested for validity. For example if you try to open a file that doesn't exist the return value might be a NULL value. There are two common strategies for dealing with these kinds of situations:

    1. include the error code in the result of the function or
    2. set a global variable to an error status.

    In either case its up to the programmer to check to see whether an error has occurred and take appropriate action.

    IN BASIC this looks like:

    OPEN "A:\DATA.TXT" FOR INPUT AS #1
    IF ERR = 53 THEN 
       CALL FileNotFoundError
    ELSE
       REM CONTINUE WITH FILE HANDLING HERE
    END IF
    

    This can result in production quality programs where over half of the code is taken up with testing every action for success. This is cumbersome and makes the code hard to read (but in practice it's how the majority of programs today work). A consistent approach is essential if silly mistakes are to be avoided.

    The Exceptional Way

    In more recent programming environments an alternative way of dealing with errors has developed. This is known as exception handling and works by having functions throw or raise an exception. The system then forces a jump out of the current block of code to the nearest exception handling block. The system provides a default handler which catches all exceptions and usually prints an error message then exits.

    The exception handling block is coded rather like an if...then...else block:

    try:
       # program logic goes here
    except ExceptionType:
       # exception processing for named exception goes here
    except AnotherType:
       # exception processing for a different exception goes here
    else:
       # here we tidy up if NO exceptions are raised
    

    There is another type of 'exception' block which allows us to tidy up after an error, its called a try...finally block and typically is used for closing files, flushing buffers to disk etc. The finally block is always executed last regardless of what happens in the try section.

    try:
       # normal program logic
    finally:
       # here we tidy up regardless of the
       # success/failure of the try block
    

    Tcl has a somewhat similar mechanism using the keyword catch:

    set errorcode [catch {
        unset x
        } msg ]
    if {$errorcode != 0} {
        # handle error here
        }
    

    In this case x doesn't exist so we can't unset it. Tcl raises an exception but the catch prevents the program from aborting and instead puts the error message into the msg variable and returns a non-zero value (which can be defined by the programmer). You can then test the return value of catch in errorcode. If it is non zero then an error occured and you can examine the msg variable.

    BASIC doesn't quite support exceptions but does have a construct which helps to keep the code clear:

    100 OPEN "A:\Temp.dat" FOR INPUT AS #1
    110 ON ERROR GOTO 10010
    120 REM PROGRAM CODE HERE...
    130 ...
    10000 REM ERRORHANDLERS:
    10010 IF ERR = 54 THEN....
    

    Note the use of line numbers. This was common in older programming languages including early BASIC. Now you can do the same thing with labels:

    ON ERROR GOTO Handler
    REM Now create divide by zero error
    x = 5/0
    Handler:
       IF ERR = 23 THEN 
          PRINT "Can't divide by 0"
          x = 0
          RESUME NEXT
       END IF
    

    Notice the RESUME NEXT statements which allow us to return to just after the error and carry on with the program.

    Generating Errors

    What happens when we want to generate exceptions for other people to catch, in a module say? In that case we use the raise keyword in Python:

    numerator = 42
    denominator = input("What value will I divide 42 by?")
    if denominator == 0:
       raise "zero denominator"
    

    This raises a string object exception which can be caught by a try/except block.

    Tcl's Error Mechanism

    In Tcl the return statement takes an optional -code flag which gets caught by any enclosing catch:

    proc spam {val} {
            set x $val
            return -code 3 [expr $x]
            }
    set err [catch {
                   set foo [spam 7]
                   } msg]
    

    err should have the value 3 and msg the value 7. Once again a case where Tcl's syntax is less intuitive than it might have been.

    BASIC Error Handling

    In BASIC you can set the ERR variable with the ERROR statement:

    ON ERROR GOTO ERRORS
    INPUT "INPUT ERROR CODE"; E
    ERROR E
    
    ERRORS:
    IF ERR = 142 THEN
        PRINT "Error 142 found"
        STOP
    ELSE
        PRINT "No error found"
        STOP
    END IF
    
    


    Things to remember
  • Check error codes using an if statement
  • Catch exceptions with an except clause
  • Generate exceptions using the raise keyword
  • Errors can be a simple string
  • Previous  Next  Contents


    If you have any questions or feedback on this page send me mail at: alan.gauld@btinternet.com