Visual Basic

Using the Assert Statement: When should you assert?

Once you start using assertions seriously in your code, you need to be aware of some pertinent issues. The first and most important of these is when you should assert. The golden rule is that assertions should not take the place of either defensive programming or data validation. It is important to remember, as I stated earlier, that assertions are there to help prevent developers from creating bugs-an assertion is normally used only to detect an illegal condition that should never happen if your program is working correctly. Defensive programming, on the other hand, attempts to prevent data loss or other undesirable effects as a result of bugs that already exist.

To return to the control software of our space shuttle, consider this code:

  Function ChangeEnginePower(ByVal niPercent As Integer) As Integer
  Dim lNewEnginePower As Long
  Debug.Assert niPercent => -100 And niPercent =< 100
  Debug.Assert mnCurrentPower => 0 And mnCurrentPower =< 100
  lNewEnginePower = CLng(mnCurrentPower) + niPercent
  If lNewEnginePower < 0 Or lNewEnginePower > 100
  Err.Raise vbObjectError + mgInvalidEnginePower
  Else
  mnCurrentPower = lNewEnginePower
  End If
  ChangeEnginePower = mnCurrentPower
  End Sub

Here we want to inform the developer during testing if he or she is attempting to change the engine thrust by an illegal percentage, or if the current engine thrust is illegal. This helps the developer catch bugs during development. However, we also want to program defensively so that if a bug has been created despite our assertion checks during development, it won't cause the engine to explode. The assertion is in addition to some proper argument validation that handles nasty situations such as trying to increase engine thrust beyond 100%. In other words, don't ever let assertions take the place of normal validation.

Defensive programming like the above is dangerous if you don't include the assertion statement. Although using defensive programming to write what might be called nonstop code is important for the prevention of user data loss as a result of program crashes, defensive programming can also have the unfortunate side effect of hiding bugs. Without the assertion statement, a programmer who called the ChangeEnginePower routine with an incorrect argument would not necessarily receive any warning of a problem. Whenever you find yourself programming defensively, think about including an assertion statement.

Explain your assertions

Perhaps the only thing more annoying than finding an assertion statement in another programmer's code and having no idea why it's there is finding a similar assertion statement in your own code. Document your assertions. A simple one- or two-line comment will normally suffice-you don't need to write a dissertation. Some assertions can be the result of quite subtle code dependencies, so in your comment try to clarify why you're asserting something, not just what you're asserting.

Beware of Boolean coercion

The final issue with Debug.Assert is Boolean type coercion. Later in this chapter, we'll look at Visual Basic's automatic type coercion rules and where they can lay nasty traps for you. For now, you can be content with studying the following little enigma:

  Dim nTest As Integer
  nTest = 50
  Debug.Assert nTest
  Debug.Assert Not nTest

You will find that neither of these assertions fire! Strange, but true. The reason has to do with Visual Basic coercing the integer to a Boolean. The first assertion says that nTest = 50, which, because nTest is nonzero, is evaluated to TRUE. The second assertion calculates Not nTest to be -51, which is also nonzero and again evaluated to TRUE.

However, if you compare nTest and Not nTest to the actual value of TRUE (which is -1) as in the following code, only the first assertion fires:

  Debug.Assert nTest = True
  Debug.Assert Not nTest = True

Some final thoughts Debug.Assert is a very powerful tool for bug detection. Used properly, it can catch many bugs automatically, without any human intervention. (See the discussion of an Assertion Sourcerer for a utility that supplements Debug.Assert.) Also see Chapter 1 for further discussion of Debug.Assert.