Sub f(ByVal i As Integer, ByVal s As String) End Sub
This procedure is called by the following code:
Dim i As Integer, s As String s = "Hello" i = 1234 Call f(s, i)
You'll notice I put the parameters in the wrong order.
With pre-OLE versions of Visual Basic you get a Parameter Type Mismatch error at compile time, but in Visual Basic 4, 5, and 6 the situation is the same as in the previous example-a run-time type mismatch, depending on the value in s, and whether the implicit CInt could work.
Instead, the procedure could be defined using Variants:
Sub f(ByVal i As Variant, ByVal s As Variant) End Sub
The problem is that you might reasonably expect that after assigning 6.4 to x in the procedure subByRef, which is declared in the parameter list as a Variant, Debug.Print would show 6.4. But instead it shows only 6.
Now no run-time errors or compile-time type mismatch errors occur. Of course, it's not necessarily so obvious by looking at the declaration what the parameters mean, but then that's what the parameter name is for.
Returning to our survey of how Variants behave compared to simple data types, we now look at expressions involving Variants.
I have already suggested, for the purposes of assignment and function parameters and return values, that using Variants cuts down on problematic run-time errors. Does this also apply to the use of Visual Basic's own built-in functions and operators? The answer is, "It depends on the operator or function involved."
Arithmetic operators All the arithmetic operators (such as +, -, *, \, /, and ^) evaluate their parameters at run time and throw the ubiquitous type mismatch error if the parameters do not apply. With arithmetic operators, there is neither an advantage nor a disadvantage to using Variants instead of simple data types; in either case, it's the value, not the data type, that determines whether the operation can take place. In Example A, we get type mismatch errors on both lines:
Dim s As String, v As Variant s = "Fred" v = "Fred" s = s - s v = v - v
But in Example B, these lines both succeed:
Dim s As String, v As Variant s = "123" v = "123" s = s - s v = v - v
A lot of implicit type conversion is going on here. The parameters of "-" are converted at run time to Doubles before being supplied to the subtraction operator itself. CDbl("Fred") does not work, so both lines in Example A fail. CDbl("123") does work, so the subtraction succeeds in both lines of Example B.
There is one slight difference between v and s after the assignments in Example B: s is a string of length 1 containing the value 0, while v is a Variant of subtype Double containing the value 0. The subtraction operator is defined as returning a Double, so 0 is returned in both assignments. This is fine for v - v, which becomes a Variant of subtype Double, with value 0. On the other hand, s is a string, so CStr is called to convert the Double value to 0.
All other arithmetic operators behave in a similar way to subtraction, with the exception of +.
Option "Strict Type Checking"
Some other authors have argued for the inclusion of another option along the lines of "Option Explicit" that would enforce strict type checking. Assignment between variables of different types would not be allowed and such errors would be trapped at compile time. The conversion functions such as CInt and CLng would need to be used explicitly for type conversion to take place.
This would effectively return the Visual Basic language to its pre-OLE style, and Examples A, B, and C would all generate compile-time errors. Example D would still return a run-time type mismatch, however.
Examples E, F, and G would succeed with the same results as above. In other words, code using Variants would be unaffected by the feature.
Comparison operators We normally take the comparison operators (such as <, >, and =) for granted and don't think too much about how they behave. With Variants, comparison operators can occasionally cause problems.
The comparison operators are similar to the addition operator in that they have behavior defined for both numeric and string operands, and unfortunately this behavior is different.
A string comparison will not necessarily give the same result as numeric comparison on the same operands, as the following examples show:
Dim a, b, a1, b1 a = "1,000" b = "500" a1 = CDbl(a) b1 = CDbl(b) ' Now a1 > b1 but a < b
Notice also that all four variables-a, b, a1, and b1-are numeric in the sense that IsNumeric will return True for them.
As with string and number addition, the net result is that you must always be aware of the potential bugs here and ensure that the operands are converted to a numeric or string subtype before the operator is used.
Visual Basic's own functions
Visual Basic's own functions work well with Variants, with a few exceptions. I won't cover this exhaustively but just pick out some special points.
The Visual Basic mathematical functions works fine with Variants because they each have a single behavior that applies only to numerics, so there is no confusion. In this way, these functions are similar to the arithmetic operators. Provided the Variant passes the IsNumeric test, the function will perform correctly, regardless of the underlying subtype.
a = Hex("1,234") a = Log("1,234") 'etc.. No problems here
Type mismatch errors will be raised should the parameter not be numeric.
The string functions do not raise type mismatch errors, because all simple data types can be converted to strings (for this reason there is no IsString function in Visual Basic). Thus, you can apply the string functions to Variants with numeric subtypes-Mid, InStr, and so forth all function as you would expect. However, exercise extreme caution because of the effect regional settings can have on the string version of a numeric. (This was covered earlier in the chapter.)
The function Len is an interesting exception, because once again it has different behavior depending on what the data type of the parameter is. For simple strings Len returns the length of the string. For simple nonstring data Len returns the number of bytes used to store the variable. However, less well known is the fact that for Variants, it returns the length of the Variant as if it were converted to a string, regardless of the Variant's actual subtype.
Dim v As Variant, i As Integer i = 100 v = i ' The following are now true: ' Len(i) = 2 ' Len(v) = 3
This provides one of the only ways of distinguishing a simple Integer variable from a Variant of subtype Integer at run time.