The meaning of zero

Null, IsNull, Nothing, vbNullString, "", vbNullChar, vbNull, Empty, vbEmpty… Visual Basic 5 has enough representations of nothing and zero to confuse the most careful programmer. To prevent bugs, programmers must understand what each of these Visual Basic keywords represents and how to use each in its proper context. Let’s start with the interesting stuff.

Private sNotInitString As String
Private sEmptyString As String
Private sNullString As String
sEmptyString = ""
sNullString = 0&

Looking at the three variable declarations, a couple of questions spring to mind. What are the differences between sNotInitString, sEmptyString, and sNullString? When is it appropriate to use each declaration, and when is it dangerous? The answers to these questions are not simple, and we need to delve into the murky depths of Visual Basic’s internal string representation system to understand the answers.

After some research and experimentation, the answer to the first question becomes clear but at first sight is not very illuminating. The variable sNotInitString is a null pointer string, held internally as a pointer that doesn’t point to any memory location and that holds an internal value of 0. sEmptyString is a pointer to an empty string, a pointer that does point to a valid memory location. Finally, sNullString is neither a null string pointer nor an empty string but is just a string containing 0.

Why does sNotInitString contain the internal value 0? In earlier versions of Visual Basic, uninitialized variable-length strings were set to an empty string internally. Ever since the release of Visual Basic 4, however, all variables have been set to 0 internally until initialized. Developers don’t normally notice the difference because, inside Visual Basic, this initial zero value of uninitialized strings always behaves as if it were an empty string. It’s only when you go outside Visual Basic and start using the Windows APIs that you’ll receive a shock. Try passing either sNotInitString or sEmptyString to any Windows API function that takes a null pointer. Passing sNotInitString will work fine because it really is a null pointer, whereas passing sEmptyString will cause the function to fail. Of such apparently trivial differences are the really nasty bugs created.

Private Declare Function FindWindow Lib "user32" Alias _
    "FindWindowA" (ByVal lpClassName As Any, _
                   ByVal lpWindowName As Any) As Long

Dim sNotInitString As String
Dim sEmptyString As String
Dim sNullString As String

sEmptyString = ""
sNullString = 0&

Shell "Calc.exe", 1
DoEvents
' This will work.
x& = FindWindow(sNotInitString, "Calculator")

' This won't work.
x& = FindWindow(sEmptyString, "Calculator")

' This will work.
x& = FindWindow(sNullString, "Calculator")

Now that we’ve understood one nasty trap and why it occurs, the difference between the next two variable assignments becomes clearer.

sNullPointer = vbNullString
sEmptyString = ""

It’s a good idea to use the former assignment rather than the latter, for two reasons. The first reason is safety. Assigning sNullPointer as here is the equivalent of sNotInitString in the above example. In other words, it can be passed to a DLL argument directly. However, sEmptyString must be assigned the value of 0&before it can be used safely in the same way. The second reason is economy. Using "" will result in lots of empty strings being scattered throughout your program, whereas using the built-in Visual Basic constant vbNullString will mean no superfluous use of memory.

Null and IsNull are fairly clear. The only hazard here is a temptation to compare something with Null directly, because Null will propagate through any expression that you use. Resist the temptation and use IsNull instead.

' This will always be false.
If sString = Null Then
    ' Some code here
End If

Continuing through Visual Basic 5’s representations of nothing, vbNullChar is next on our travels. This constant is relatively benign, simply CHR$(0). When you receive a string back from a Windows API function, it is normally null-terminated because that is the way the C language expects strings to look. Searching for vbNullChar is one way of determining the real length of the string. Beware of using any API string without doing this first, because null-terminated strings can cause some unexpected results in Visual Basic, especially when concatenated.

Finally, two constants are built into Visual Basic for use with the VarType function. vbNull is a value returned by the VarType function for a variable that contains no valid data. vbEmpty is returned by VarType for a variable that is uninitialized. Better people than I have argued that calling these two constants vbTypeNull and vbTypeEmpty would better describe their correct purpose. The important point from the safety point of view is that vbEmpty can be very useful for performing such tasks as ensuring that the properties of your classes have been initialized properly.