When I first heard the term “exception handling” as a replacement for “error handling” I was not impressed. At first glance it seemed like political correctness gone wild and brought into computer science. I’d been calling it error handling for a long long time and it worked for me. Why change the term now? In fact this article in the Microsoft knowledgebase refers to “structured error handling.”
I’ve given this a bunch of thought lately. It really started as I was doing a set of workshops on Visual Basic .NET a month or so ago. One of the key changes between VB .NET and older versions of Visual Basic is that error handling (the OnError statement) has been replaced (for the most part) by exception handling. I see exception handling as a super set of error handling. Error handling implies that someone or some thing made an error – did something wrong. Exception handling implies that as well but it more broadly implies that something happened that was unexpected.
As I see it an error is the user’s fault and an exception (something unexpected) is the programmer’s fault. The programmer should expect things to go wrong and should prepare for that certainty. Now one can never make anything idiot proof because God keeps making better idiots but one has to try.
Recently Patrick Godwin (@ximplosionx) started a conversation on Twitter about exception handling with the question “Why are we taught to handle exceptions rather than prevent them? I would think the best way to handle it is to stop it.” The answer really is that what we want to program to do is to handle a situation caused by something going wrong in a way that is at worst helpful to the user and at best transparent to the user.
What this means is that we have to do a number of things to protect the user from themselves and protect the program from doing “bad things.” Perhaps the worst bad thing is to do the wrong thing without telling anyone what is going on. So let’s look at a couple of simple examples.
The first is simple range checking. If we are expecting a number between 1 and 100 a program should check that data. The program should go no further if the number it gets from a user, a data file, or other source until the number is corrected. I see that as data validation. Is it also exception handling? Yes though to be honest we don’t have to “throw an exception” using something like a Try/Catch structure. We can use a simple loop for example. Generally back in the old OnError days that is what programmers did and it is still a good way to do things. Of course we also try to help prevent this sort of thing by asking the user specifically what we need for input. And if they give the program the wrong data or put another way exceptional or otherwise unexpected data we want the program to explain what went wrong.
Some of exception handling is dependent on where you want to handle things. Take for example the case of a divide by zero error. One can catch it when it happens:
Try sum = a \ b Catch ex As DivideByZeroException MessageBox.Show(ex.Message) Return End Try
or one can stop it before it happens by validating the data earlier. For example:
b = System.Convert.ToInt32(Me.txtNumber1.Text) If b < 0 Then MessageBox.Show("Value must be greater than zero, please try again...") Me.txtNumber1.SelectAll() Me.txtNumber1.Focus() Return End If
Which is better? I’m not sure there is a clear answer. On one hand validating the data earlier is a good thing especially if the data is likely to be used for something else that would not generate an error but which would generate other bad data. On the other hand there are more things that could go wrong with that data conversion so perhaps something like this would also be a good idea:
Try '** validate second input… b = System.Convert.ToInt32(Me.txtNumber2.Text) Catch ex As Exception MessageBox.Show(ex.Message) Me.txtNumber2.SelectAll() Me.txtNumber2.Focus() Return End Try
And then do we check for out of range or do we wait until the divide operation? Or maybe something like:
Try '** validate second input… b = System.Convert.ToInt32(Me.txtNumber2.Text) Catch ex As Exception MessageBox.Show(ex.Message) Me.txtNumber2.SelectAll() Me.txtNumber2.Focus() Return Finally If b < 0 Then MessageBox.Show("Value must be greater than zero, please try again...") Me.txtNumber1.SelectAll() Me.txtNumber1.Focus() End If End Try
This data validation gets complicated pretty quickly doesn’t it? And you know what? There is still a chance that the value of b will get modified in bad ways before we get to the division operation. We may want to keep that Try/Catch anyway.
Where it gets complicated for real is where the user can’t really do anything about what went wrong. Those are cases where we as programmers really want to avoid. Whether we use exception handling or error handling or structured error handling is not as important as preventing unrecoverable errors from happening. What do we do if that does happen? Well then we need to report as much information as possible in a form that they user can get to the developer. End users are generally not the best reporters of fatal errors. The program is going to have to do that. It may be an error log file (in which case the user needs to know where that file is and what to do with it) or it might be a detailed error message. Again what will the user do with that message?
These days Microsoft Windows has some built in reporting tools for fatal errors. It might be the OS, a driver or even an application program. This process sends information to Microsoft where it is analyzed and when possible passed on to the right development group for fixing. This has been a powerful and very successful tool for reducing the number of errors and making Windows and Windows applications more stable and robust. And that is a good thing. It’s the kind of thinking that we need people to learn early on in their careers though. A first programming course is not too soon to start.