Visual Basic

Defensive Coding

I have extolled the virtues of using Variants and the flexibility that they give. To be more precise, they allow the interface to be flexible. By declaring the number of books to be a Variant, you make it unlikely that the data type of that parameter will need to be modified again.

This flexibility of Variants has a cost to it. What happens if we call the function with an input that doesn't make sense?

N = ReadBooks("Ugh")

Inside the function, we are expecting a number-so what will it make of this? If we are performing some arithmetic operations on the number, we risk a type mismatch error when a Variant with these contents is passed. You must assert your preconditions for the function to work. If, as in this instance, the input must be numeric, be sure that this is the case:

Function ReadBooks(ByVal input As Variant) As Variant
      If IsNumeric(input) Then
          ' Do stuff, return no error
      Else
          ' Return error
      End If
  End Function

In other words, you code defensively by using the set of Is functions to verify that a parameter is suitable for the operation you're going to perform on it.

You might think about using Debug.Assert in this instance, but it is no help at run time because all the calls to the Assert method are stripped out in compilation. So you would still need to implement your own checks anyway.

Of course, verifying that your input parameter is appropriate and satisfies the preconditions is not just about checking the type. It would also involve range checks, ensuring that we are not dividing by 0, and so on.

Is this feasible? In practice, coding defensively like this can become a major chore, and it is easy to slip up or not bother with it. It would be prudent if you were writing an important piece of component code, especially if the interface is public, to place defensive checks at your component entry points. But it is equally likely that a lot of the time you will not get around to this.

What are the consequences of not performing the defensive checks? While this naturally depends on what you are doing in the function, it is most likely that if there is an error it will be a type mismatch error. If the string Ugh in the previous example was used by an operator or built-in function that only worked with numerics, a type mismatch would occur. Interestingly, had the parameter to ReadBooks been declared as a Double instead of a Variant, this same error would be raised if the string Ugh was passed.

The only difference is that in the case of the Variant the error is raised within the function, not outside it. You have the choice of passing this error back to the calling client code or just swallowing the error and carrying on. The approach you take will depend on the particular circumstances and your preferences.