Tuesday, February 24, 2015

...Finally


One of the most powerful, but misused logical constructs in programming is the exception. Exceptions provide the programmer with an exit strategy in the event of a runtime error. Any section of code that could fail should be wrapped in a "try" block. If an error occurs within that "try" block then an exception is thrown and any code in the subsequent "catch" block will get executed. Conveniently, in most languages that support exception handling, the reason for the failure is also passed into the "catch" block. This allows the programmer to check why the failure occurred and handle it appropriately.
Unfortunately, more often than not, programmers either simply ignore the exception and move on or pass the exception on to the user and exit the program. You will see this on far too many websites. No user should ever be exposed to an exception. In my mind, displaying an exception to a user is the programming equivalent of dropping one's pants.
Most programming languages that support exception handling offer a third optional code block known as "finally". The "finally" code block is always executed after the completion of the "try" or "catch" blocks. I have seen far too much code in my career that contains no "finally" block, but does contain duplicate code in both the "try" and "catch". In extreme cases I have seen complex code within the "catch" block that is highly likely to throw its own exceptions under certain circumstances. Any code within the "catch" block should be as simple as possible.
Consider the following ASP.Net C# console application. This application accepts commmand-line arguments and displays them back to the user. A common command-line structure accepts arguments that begin with a dash character ("-") as options with parameters immediately following. For example, "hello -name Brad" would tell the "hello" application to accept a "name" parameter with the value of "Brad". For web developers this is similar to the querystring.
A console program consumes the arguments in a globally scoped array called "args":


 static void Main(string[] args)


In this intentionally buggy example, we echo back the arguments to the user. If the user passes "-name Brad LiveResponse -color Red" then the program will echo:

 Total number of command line argument values: 5
 Arguments...
  name=Brad
  LiveResponse
  color=Red


But if the user passes "-name Brad LiveResponse -color" then the program will fail with the following output:

 Total number of command line argument values: 4
 Arguments...
  name=Brad
  LiveResponse
 Exception: Index was outside the bounds of the array.


The exception occurs due to the following bad logic:

 for (int i = 0; i < args.Length; i++)
 {
  if (args[i][0] == '-')
  {
   Console.WriteLine("\t" + args[i].Substring(1) + "=" + args[++i]);
  }
  else
  {
   Console.WriteLine("\t" + args[i]);
  }
 }


In this logic we assume that when an argument that begins with a dash character is provided then the user will always be kind and provide a value after it. But if the user passes "-name Brad LiveResponse -color" the line "Console.WriteLine("\t" + args[i].Substring(1) + "=" + args[++i]);" will cause a runtime error as it will be incrementing the loop counter "i" beyond the end of the "args" array expecting a value for the color parameter.
So now we have a program with a runtime error that is easy to produce. Why did I choose to demonstrate this with a console application? Any time you run a console application from the debugger it will simply exit when it is done. A program like this runs so quickly that you may never see it execute. In order to see the program execute you will need to insert logic that causes the program to wait before closing. In this example I added:

 Console.ReadLine();


This forces the program to wait until the user hits the enter key, allowing us to see the output. In this example we will always want to run this line before the program exits whether an exception occurs or not. This is where the "finally" block comes into play. If you were to put that line within the "try" block it will get executed only if there is no error:

 for (int i = 0; i < args.Length; i++)
 {
  if (args[i][0] == '-')
  {
   Console.WriteLine("\t" + args[i].Substring(1) + "=" + args[++i]);
  }
  else
  {
   Console.WriteLine("\t" + args[i]);
  }
 }
 Console.ReadLine();


You could put it inside both the "try" and "catch" blocks:

 Console.WriteLine("Exception: " + ex.Message);
 Console.ReadLine();


But if you do that then you've added the same line of code in two different places. This introduces additional maintenance and quality risk if you ever want to change the "end of program" wait action to something else. Instead, add a "finally" block after the catch. This block of code will get executed whether an exception occurs or not:

 finally
 {
  Console.ReadLine();
 }


Note that the "finally" block will still get executed even if the code in the "try" or "catch" block returns to the calling operation before completion.
Consider another example of an application that opens connections to a database. These connections must be closed. By placing the close methods within your "finally" block you can ensure that the connections don't remain open in the event of an error.
The "finally" block allows you to simplify your program by placing any actions together that must get executed every time, whether there is an error or not.

The whole example program follows. If you would like to see it in action, create a C# console application in Visual Studio and replace the program code with this. I intentionally wrote this program with an error in it. Try it out.
  • Run it with a variety of command-line options and see how many ways you can break it.
  • Move the "Console.Readline();" statement into the "try" or "catch" block to see what happens.
  • Add a "throw" statement into your "try" or "catch" to see what happens (hint: a "throw" in the "catch" block produces very interesting results).
  • And, for fun, see if you can write a more robust and terse command-line parser and post it in the comments below.
  • 
     using System;
    
     class Program
     {
      static void Main(string[] args)
      {
       try
       {
        Console.WriteLine("Count: {0}\r\nArguments...", args.Length);
        for (int i = 0; i < args.Length; i++)
        {
         if (args[i][0] == '-')
         {
          //If the argument begins with a dash, include its parameter
          // in the output.
          //If the last argument begins with a dash this line will
          // throw an exception.
          Console.WriteLine("\t"+args[i].Substring(1)+"="+args[++i]);
         }
         else
         {
          //Otherwise just write the argument
          Console.WriteLine("\t" + args[i]);
         }
        }
       }
       catch (Exception ex)
       {
        //The above code with throw an exception
        // if the last argument begins with a dash.
        Console.WriteLine("Exception: " + ex.Message);
       }
       finally
       {
        //Whether an exception is thrown or not this line is
        // always executed.
        Console.ReadLine();
       }
      }
     }