CS320 Lecture: Exceptions                               revised 10/2/97

Need: Handout / Transparency of stack with exception handling
      Handout / Transparency: contorted example

I. Motivation
-  ----------

   A. An important property of software is ROBUSTNESS: the ability to respond
      reasonably to anomalous conditions

      1. In simple applications, primarily arising from malformed input or
         bad input values

      2. In embedded systems, includes other problems such as hardware failures,
         abnormal events etc.

   B. Three general approaches:

      1. Defensive programming - test everything first

         Ex: don't read directly into an integer variable - read into a
             string, then check format, then convert

         (Only way to deal with malformed input in standard Pascal)

         Ex: test data values for legitimacy before using

         Problems:

         - Can get very burdensome, lead to code size inflation
         - Does not cope well with all kinds of problems (how do you defend
           against a hardware failure that occurs just after you've checked
           it to be sure it's good!)

      2. Use of status flags that programmer can test after performing an
         operation

         Ex: state of an iostream in C++:   if (stream.good()) or if (! stream)

         Ex: many standard C library routines set a global variable errno to a
             non-zero value if they fail

         Ex: most VAX system services and run time library routines return a
             status code - odd if successful

         Problems:

         - Can get very burdensome, lead to code size inflation
         - Easy to forget or not want to bother

      3. Exception handling mechanism - found in many modern languages:

         PL1 - first major language to do this
         Modern dialects of LISP
         Ada
         C++    
         Java

         Each language does this in a somewhat different way, but
         the basic idea is to cause an orderly, well-defined interruption in
         the flow of program control when an exceptional condition arises

II. C++ Exception handling
--  --- --------- --------

   A. A feature added to the language in 1989 after 5 years of work.  Not yet
      implemented by many C++ compilers.

      Ex: gnu c++ 2.3 (which we have been using on Faith) does not; 
          2.7 (on Linus and newly installed on Faith) does, but only
          if you include -fhandle-exceptions on compile command line.
          (Exception handling is not turned on by default in gnu c++ 2.7 
          because the implementation is still brittle.)

      To turn on exception handling on faith: 

                gcc/plus/cc1=-fhandle-exceptions file.cc

   B. Not used by older standard libraries such as iostream, which were
      designed before this facility was commonly available.

   C. Two key ideas:

      1. A routine that detects an exceptional condition can THROW an
          exception.

      2. A routine that anticipates that an exception might occur either in
         its own code or that of a routine it calls (directly or indirectly)
         can CATCH the exception.

   D. Example: Stack template with exceptions built in

      HANDOUT + TRANSPARENCY
        
      DEMO

      Note: 

      1. throw statement.  throw is a reserved word.  throw always
         throws something, which can be a value of a standard type or
         an object - either explicitly specified or implied

         Syntax:
                throw expression;
          or
                throw;  // to rethrow a previous exception

      2. try statement.  try is a reserved word.  "Wraps" code that
         might cause an exception to be thrown (directly or by a
         routine it calls).

         Syntax:
                try
                  {
                    ...
                  }

      3. catch statement.  catch is a reserved word that introduces an
         exception handler.  One or more handlers immediately follow a 
         try block to indicate willingness to catch an exception of a
         certain type.

         Syntax: 
                catch (TYPE PARAMETER)
                  {
                    ...
                  }

   E. Exceptions that are thrown are matched with a handler based on the TYPE
      of the exception thrown.

      Example: The exceptions thrown by the stack routines are of type char *,
               and the handler catches an exception of type char *. Any
               other type of thrown object would not be caught by this handler.

      1. The C++ runtime maintains a list of outstanding try blocks (blocks that
         have not exited).  When an exception is thrown, the handler(s) for each
         are tried in LIFO order until one is found that handles an exception of
         the type thrown, or all have been tried (in which case the program
         aborts)

         a. Any intervening blocks are exited immediately (without completing
            execution)  and local objects declared in them are destroyed.

         b. When a handler is found, its code is executed, at which point the
            try statement is considered to have completed (i.e. the rest of the 
            try statement after the point where the exception was thrown is not
            executed.)  In effect, the handler replaces the latter part of the 
            try statement.

         c. The exception that was thrown is bound to the parameter declared in 
            the catch statement, and its value may be used by the handler.

      2. A "catch-all" handler that responds to any exception can be declared by
         catch (...).  Of course, in such a handler the exception itself is not
         accessible, since there is no parameter for it to be bound to.

   F. A handler can itself throw an exception, in which case the process of
      exception handling begins all over with the next previous try 
      statement.  The exception that is thrown can be a new one, or a 
      handler can rethrow the same exception by just saying throw ;

      Example: Contorted exception demo

        HANDOUT + TRANSPARENCY

        DEMO

III. Using Exceptions in the ATM problem
---  ----- ---------- -- --- --- -------

   A. Where might we use exceptions instead of status codes in the ATM machine 
      example?

   ASK

      - CardReader: to report an improperly inserted card
      - EnvelopeAcceptor: to report a timeout
      - Bank: to report disapproval of a transaction - perhaps two kinds of
        exceptions: invalidPIN (can be caught, PIN re-entered, and transaction
        retried); rejectedTransaction (transaction as a whole must fail)

   B. These exceptions are probably best modelled by Classes, rather than simple
      types.  (In fact, in industrial C++ programming that is typically the 
      case).

      Thus, we might have:

           class InvalidCardException
             {
               public: InvalidCardException();
             };

           class EnvelopeTimeoutException
             {
               public: EnvelopeTimeoutException();
             };

           class InvalidPINException
             {
               public:  InvalidPINException(Transaction & transaction);
                        Transaction & transaction();
               private: Transaction & _transaction;
             }

           class RejectedTransactionException
             {
                public:  RejectedTransactionException(const char * reason);
                         const char * reason();
                private: const char * _reason;
             }

      Note that the first two classes have no data and no method except a
      constructor. Everything that one needs to know about these exceptions
      is contained in their type - e.g. one could have
  
           throw InvalidCardException();

      and

           catch(InvalidCardException)

      and that would suffice.

      The latter two classes do carry additional information in the exception
      object that the handler can extract and use.

Copyright ©1998 - Russell C. Bjork