Evil Type Coercion

A programmer on my team had a surprise when writing Visual Basic code to extract information from a SQL Server database. Having retrieved a recordset, he wrote the following code:

Dim vntFirstValue As Variant, vntSecondValue As Variant
Dim nResultValue1 As Integer, nResultValue2 As Integer

vntFirstValue = Trim(rsMyRecordset!first_value)
vntSecondValue = Trim(rsMyRecordset!second_value)

nResultValue1 = vntFirstValue + vntSecondValue
nResultValue2 = vntFirstValue + vntSecondValue + 1

He was rather upset when he found that the “+” operator concatenated the two variants but added the final numeric value. If vntFirstValue contained “1” and vntSecondValue contained “2”, nResultValue1 had the value 12 and nResultValue2 had the value 13.

To understand exactly what’s going on here, we have to look at how Visual Basic handles type coercion. Up until Visual Basic 3, type coercion was relatively rare. Although you could write Visual Basic 3 code like

txtBox.Text = 20

and find that it worked without giving any error, almost every other type of conversion had to be done explicitly by using statements such as CStr and CInt. Starting with Visual Basic 4, and continuing in Visual Basic 5, performance reasons dictated that automatic type coercion be introduced. Visual Basic no longer has to convert an assigned value to a Variant and then unpack it back into whatever data type is receiving the assignment. It can instead invoke a set of hard-coded coercion rules to perform direct coercion without ever involving the overhead of a Variant. Although this is often convenient and also achieves the laudable aim of good performance, it can result in some rather unexpected results. Consider the following code:

Sub Test()

Dim sString As String, nInteger As Integer
sString = "1"
nInteger = 2
ArgTest sString, nInteger

End Sub

Sub ArgTest(ByVal inArgument1 As Integer, _
            ByVal isArgument2 As String)
' Some code here
End Sub

In Visual Basic 3, this code would give you an immediate error at compile time because the arguments are in the wrong order. In Visual Basic 4 and Visual Basic 5, you won’t get any error because Visual Basic will attempt to coerce the string variable into the integer parameter and vice versa. This change is not a very pleasant one. If inArgument1 is passed a numeric value, everything looks and performs as expected. As soon as a nonnumeric value or a null string is passed, however, a run-time error occurs. This means that the detection of certain classes of bugs has been moved from compile time to run time, which is definitely not a major contribution to road safety.

The table at the top of the following page shows Visual Basic 5’s automatic type coercion rules.

Source Type Coerced To Apply This Rule
Integer Boolean 0=False, nonzero=True
Boolean Byte False=0, True=255
Boolean Any numeric False=0, True=-1 (except Byte)
String Date String is analyzed for MM/dd/yy and so on
Date Numeric type Coerce to Double and use DateSerial(Double)
Numeric Date Use number as serial date, check valid date range
Numeric Byte Error if negative
String Numeric type Treat as Double when representing a number

Some Final Thoughts Any Visual Basic developer with aspirations to competence should learn the automatic type coercion rules and understand the most common situations in which type coercion’s bite can be dangerous.