Bug Vanquisher

23 December 2007

Catching the Exceptional

Filed under: Computer Theory, Dev inside! — Tanveer Badar @ 4:42 PM

[Warning: None of the code, even the simplest one, may compile. I was just demonstrating a point, code is meta-information to support that.]

Let’s do some coding. You have a simple program to calculate inverse of an integer.

using System;

namespace Program
{
    public class Exceptional
   {
       public static void Main( )
       {
           Func( );
       }

       void ShowInverse( int num )
       {
           Console.WriteLine( 1.0 / ( double )num );
       }

       void Func( )
       {
           Console.WriteLine( "Please enter a number: " );
           try
           {
               int num = int.Parse( Console.ReadLine( ) );
               ShowInverse( num );
           }
           catch( Exception ex )
           {
               Console.WriteLine( ex.Message );
           }
        }
    }
}

I do not claim this program to be the best ever. You will see what I am trying to do. That int.Parse line can fail for any number of reasons. That’s why it is surrounded by a try-catch clause. So, we got rid of formatting errors for the moment. But this leaves one problem wide open. What happens if input is ‘0’? We may need to add another try-catch in ShowInverse. So the revised code for ShowInverse becomes

       void ShowInverse( int num )
       {
           try
           {
               Console.WriteLine( 1.0 / ( double )num );
           }
           catch( Exception ex )
           {
               Console.WriteLine( ex.Message );
           }
       }

This is essentially equivalent to having a nested try-catch block inside the one in Func. You get the idea how we nest try-catch blocks to deal with different syntactic/semantic errors.

Now, let’s get a bit abstract, our Exceptional class has some functions which encapsulate some business logic and call each other inside try-catch clauses. Each of them has DB logging for success, in case of exceptions and in their finally blocks.

using System;

namespace Program
{
   public class Exceptional
   {
       // logging logic all goes inside Logger.Log function, which will take only a string.
       Logger log = new Logger( );

       void Func1( ... )
       {
           try
           {
               log.Log( "Executing Func1" );
               ...
               Func2( ... );
               log.Log( "Ending Func1's try block." );
           }
           catch( Exception ex )
           {
               log.Log( "Error occurred inside Func1 " + ex.Message );
           }
           finally
           {
               log.Log( "Exiting Func1." );
           }
        }

       void Func2( ... )
       {
           try
           {
               log.Log( "Executing Func2" );
               ...
               log.Log( "Ending Func2's try block." );
           }
           catch( Exception ex )
           {
               log.Log( "Error occurred inside Func2 " + ex.Message );
           }
           finally
           {
               log.Log( "Exiting Func2." );
           }
        }
    }
}

We log everything, even the exceptions to a database. Here’s a pop quiz, what happens in the case when original exception was thrown because underlying database is not available? Even in this case, we attempt logging and fail in our catch blocks and throw another exception.

Suppose this happened while Func2 was executing, we catch the first exception and try to log it, another exception is thrown and Func1 attempts to log it and throws yet another exception. There is no one to catch the third exception was will cause what service Exceptional was providing to fail.

Is the answer to the problem is to add yet another try-catch clause inside all existing catch/finally blocks? Definitely no. What if someone else comes along later and sees no logging in catch/finally block! I’ll add that. And we are back to the same problem we were attempting to solve.

Suppose, this code was part of a console application. Eventually, the exception would surface to operating system loader which will notice no one has handled it. For Windows, you can find the details in MSDN about what happens when program throws an unhandled exception, but operating systems follow similar patterns. If everything fails, program is terminated. If this happened in kernel mode, you lose everything.

If you pause to think for a moment, you will see our exceptional handling code forms a hierarchy. We have various levels of handlers from swallowing everything type to log and rethrow to transforming ones. At lower levels, you have all sorts of choices from retrying the operation to keeping things silent to invoking some alternative or compensating functionality.

The one which causes the program to terminate is the most beautiful. It is the root which must withstand the worst of all. It is unique in the way that nothing passes this handler, nothing can ever pass this one. It handles everything where others fail.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: