logo
 
Exceptions
CptS 355 - Programming Language Design
Washington State University
Home
Notices
Calendar
Homework
Syllabus
Resources
People

Escapes and breaks

Most programming language control structures (e.g., if-then-else) are single-entry single-exit. if E then C1 else C2
        -------------------
        |                 |
        |     true        |
   ------> E --->  C1 ---------->              
        |  |           |  |
        |   -----> C2 -   |
        |     false       |
        |                 |
        -------------------
while E do C
        ----------------------
        |                    |
        |        false       |
   ---------> E ------------------>
        | |   |              |
        | |    ------> C     |
        | |      true  |     |
        |  <-----------      |
        ----------------------
It is "easy" to follow the flow-of-control when these structures are "plugged-together" like tinker toys. While all structured control constructs can be implemented with a disciplined use of gotos, undisciplined use of goto's make reasoning about programs more difficult because they allow multiple entry/exit from program blocks. However, it is might be useful for the flow of control to jump out of the expected course. An escape is a sequencer that transfers control to the end of the enclosing block. Useful primarily in loops.
  while (not eof()) {
    if (ch == 'q') break;
    }
The control flow diagram is the following.
        ----------------------
        |                    |
        |        false       |
   ---------> E ------------------>
        | |   |              |  |
        | |    ------> C--------   
        | |      true  |     |
        |  <-----------      |
        ----------------------
The C break statement can only exit the containing block, so if we had two nested loop with the break in the inner loop, it couldn't exit from both loops. In a function, a return can act as a general escape (leave the function now).
while (...) {
  while (...) {
   if (ch == 'q') return;  /* exit both loops */
  }
}
The most drastic of all is to "halt" the entire program. In C, we can do this with an exit() function call.
while (...) {
  while (...) {
   if (error) exit(return_code);  /* exit program */
  }
}

Exceptions

An exception is an "exceptional" or unexpected condition. Common exceptions include the following.
  • arithmetic, e.g., division-by-zero
  • arrays, e.g., out-of-bounds
  • I/O, e.g., can't open file
An exception is said to be "thrown" if it is raised or signaled. Some languages have no capabilities for handling exceptions. What happens when we try to divide by zero in Pascal? In C?
  x = 0;
  z = y / x;  /* error division by zero --> core dump */
Other languages provide exception handlers. PL/1 was the first major language to provide exception handlers. In languages with exception handlers, there are several important issues to consider.
  • Which handler is called when an exception is thrown? Said differently, how is an exception handler bound or associated with an exception?
  • When an exception handler finishes, where does the program continue execution? This is known as continuation. Exceution could continue at the statement following the statement that threw the exception, at the end of the block enclosing that statement, at the end of the subprogram containing the exception, or some other place.
  • What information can be passed in an exception to the handler?
  • Can exceptions be propagated, that is, if there is no local handler, can the exception be thrown "up the stack" to other handlers?
Java provides exception handlers with the try-catch statement.
  try {
    x = 0;
    z = y / x;  // continuation is at the end of the try 
    x = z;  
  } catch (DivideByZeroException e) {
    System.out.println("Warning, tried to divide-by-zero, am continuing");
    z = 0;
  }
  ...
Java has the following model for exceptions.
  • An exception is an object. It is an instance of a class that is an descendent of the Exception class (in the inheritance hierarchy). So to create a DivideByZeroException object, we would first need to have a DivideByZeroException class that extends Exception. There are a few built-in Exception classes. A try statement may have several catch clauses. The catches are tried in sequence until one "catches". An exception is caught by a catch that matches the Exception (or is an ancestor). So if DivideByZeroException extends Exception, then a DivideByZeroException would be caught by either DivideByZeroException or Exception, but not by any other Exception, e.g., ArrayOutOfBoundsException.
  • If an exception is caught, continuation happens at the end of the try.
  • An Exception is an object, the constructor is called when the Exception is created and thrown. So all kinds of information can be passed.
  • A method can throw an Exception that is not caught within the method.
Exceptions are especially nice in I/O. Consider the standard act of opening a file and reading data into memory. There are lots of exceptions (or errors) to handle.
    readFile {
               try {
                   open the file;
                   determine its size;
                   allocate that much memory;
                   read the file into memory;
                   close the file;
               } catch (fileOpenFailed) {
                   doSomething;
               } catch (sizeDeterminationFailed) {
                   doSomething;
               } catch (memoryAllocationFailed) {
                   doSomething;
               } catch (readFailed) {
                   doSomething;
               } catch (fileCloseFailed) {
                   doSomething;
               }
           }
Note that the catch statements scans for particular kinds of errors. The alternative is to write code like this.
           errorCodeType readFile {
               initialize errorCode = 0;
               open the file;
               if (theFileIsOpen) {
                   determine the length of the file;
                   if (gotTheFileLength) {
                       allocate that much memory;
                       if (gotEnoughMemory) {
                           read the file into memory;
                           if (readFailed) {
                               errorCode = -1;
                           }
                       } else {
                           errorCode = -2;
                       }
                   } else {
                       errorCode = -3;
                   }
                   close the file;
                   if (theFileDidntClose && errorCode == 0) {
                       errorCode = -4;
                   } else {
                       errorCode = errorCode and -4;
                   }
               } else {
                   errorCode = -5;
               }
               return errorCode;
           }
But this code is very bloated, and it is unclear as to what is actually going on.

Propagating Exceptions

What happens if we call a method inside of a try statement, but detect errors in that method? A method may propagate exceptions to callees (up the call stack).
          method1 {
               try {
                   call method2;
               } catch (Exception2 e) {
                   doErrorProcessing;
               }
           }
           method2 throws Exception2 {
               call method3;
           }
           method3 throws Exception3 {
               call readFile;
           }

Source of Information

These lecture notes are based on chapter 8 in "Programming Language Concepts and Paradigms" by David Watt, Brewing Java, A Tutorial, and Chapter 14 in "Programming Languages, 6ed" by Robert Sebesta.
                                                                                                                                                                                                                                                                                                                                             
  (c) 2003 Curtis Dyreson, (c) 2004 Carl H. Hauser           E-mail questions or comments to Prof. Carl Hauser