Variables and Constants

A variable is a name for an abstract concept (such as an object, a string value, or a numeric value) in a computer program. Using variables allows us to refer to the variable by its name, rather than to focus on its implementation details. Think of the nightmare you'd have trying to keep track of just which memory location your particular piece of data was occupying (completely ignoring the possibility that its memory location might change while the program executes). Those nice people who write the software we use to create our programs and scripts solved this problem a long time ago by giving us variables and constants.

3.2.1 What Is a Variable?

A variable is a placeholder or recognizable name for a memory location. This location is of no consequence to us; all we have to do is remember the name. When we use the name, the script engine will go to the correct memory location and either retrieve the data stored there or change the data, depending upon our instructions. It is important therefore to learn the rules for namingvariables. (These in fact are the rules for naming any identifier in VBScript, including variables, functions, subs, classes, and constants.)

Variable names within VBScript are not case-sensitive, so myvar is the same as MyVar. You may have noticed in the examples so far (and if you haven't, go back and take a look) that we've used a combination of lower- and uppercase, with the first few letters usually in lowercase, for variable names like myVar. This is called camel casing. It improves readability, but is also a good habit to form; you'll see why when we discuss naming conventions.

So variables can either be a simple single character:

x = 10 y = "Hello World"

or they can be more descriptive:

tableRows = 10 greetingString = "Hello World"

Variables are so called because their value can change throughout their lifetime in your script. But you may have a requirement for a variable that isn't variable at all, whose value remains the same throughout your script. Guess what they're called?

3.2.2 What Is a Constant?

Constants perform a similar function to variables: they allow you to replace a value with a more descriptive and intuitive string. The difference is that a constant keeps the same value throughout its lifetime.

Values are assigned to constants using the same method used for variables, and can contain most of the same data types. (Constants cannot be of type Single or Object, for instance.) In most respects, therefore, a constant is the same as a variable. In fact, it could be described as a variable whose value doesn't vary!

VBScript uses the Const declaration to define a constant. Aconstant, which is declared as follows:

Const myConstant = 10

cannot have its value changed throughout the life of the program. If your script mistakenly attempts to modify its value, VBScript raises an "Illegal Assignment" error. You'll know therefore using the previous example that whenever you use myConstant in your script, you are sure to be using the value 10.

Like the constant declaration in VB, Const in VBScript cannot be used to assign nonconstant values or the values returned by VBScript functions. This means that a statement like the following:

Const numConstant = myVar ' Invalid

is invalid, since it attempts to assign the value of a variable to a constant. It also means that a statement like:

Const long_Int_Len = Len(lNum) ' Invalid

is invalid, since it relies on the value returned by the VBScript Len function. Finally, unlike VB or VBA, you are not allowed to use any value that includes an operator in defining a constant. For example, the following declaration, which is valid in VB, generates a syntax error in VBScript:

Const added_Const = 4 + 1 ' Invalid

3.2.3 Intrinsic Constants

In addition to allowing you to define your own constants using the Const keyword, VBScript includes a number of built-in or intrinsic constants whose values are predefined by VBScript. Along with saving you from having to define these values as constants, the major advantage of using intrinsic constants is that they enhance the readability of your code. So, for instance, instead of having to write code like this:

If myObject.ForeColor = &hFFFF Then

you can write:

If myObject.ForeColor = vbYellow Then

Intrinsic constants are available for the following:

Appendix B contains a complete listing of the built-in constants, along with their meanings and values.

3.2.4 Constants in Type Libraries

Type library files provide definitions of enumerated constants as well as of COM classes and their members (that is, of their properties, methods, and events). If you're developing either ASP or WSH scripts, you can make type library definitions accessible to your script. In that case, they are treated just as if they were intrinsic VBScript constants, and you don't have to define them yourself by using innumerable Const statements.

In ASP, you can make constants in type libraries available to all of the pages of your ASP application by including a METDATA tag in Global.asa. This offers significantly improved performance over a common alternativeusing the ASP #include preprocessor directive on a page-by-page basis. Its syntax is:

FileName" UU VERSION="MajorVersionNumber.MinorVersionNumber" LCIS="LocaleID"

where its parameters are as follows:

FileName

Optional. The physical path and name of the type library file. (Type libraries are often stored with the .DLLs that they describe, and can also be housed in separate files with an extension of .tlb or .olb.) While optional, either FileName or TypeLibraryUUID must be specified to identify the type library.

TypeLibraryUUID

Optional. The universally unique identifier of the type library, as defined in the HKEY_CLASSES_ROOTTypeLib key of the registry. While optional, either FileName or TypeLibraryUUID must be specified in order to identify the type library.

MajorVersionNumber

Optional. The major version number of the type library. If you include a MajorVersionNumber, you must also include a MinorVersionNumber. If version number information is specified and ASP cannot find the library with that version, a runtime error occurs.

MinorVersionNumber

Optional. The minor number of the type library. If you include a MinorVersionNumber, you must also include a MajorVersionNumber. If version information is specified and ASP cannot find the library with that version, a runtime error occurs.

LocaleID

Optional. The locale to use for this type library if the library supports multiple locales. If a LocaleID is specified that cannot be found in the type library, a runtime error occurs.

For example, the following code from Global.asa makes the enumerated constants in the ADO 2.5 type library accessible to an ASP application:

In WSH, you can make constants in a type library available to your script by including the tag in a script in a .wsf file. The constants are available only to the script within a single tag. The syntax of is:

progID" |gu="" [version="version" ]="">

with the following parameters:

progID

Optional. The version-independent or version-dependent programmatic identifier of the type library, as defined in the system registry. You must specify either ProgID or typeLibGUID.

typelibGUID

The globally unique identifier (GUID) of the type library, as defined in the system registry. This is the most common way to reference and access a type library from WSH. You must specify either ProgID or typelibGUID.

version

The version number of the type library your script needs to access.

For example, the following code makes the constants defined in Data Access Objects Version 5.0 available to a WSH script:

 

3.2.5 Declaring Variables and Constants

Unlike many other programming languages, VBScript allows the implicit declaration of variables. This means that as soon as you use a variable within your script, VBScript does all the necessary work of allocating memory, etc., and the variable is considered to be declared. However, it is good programming practice to explicitly declare any variables you want to use at the start of the procedure or script by using the Dim statement. Its syntax is:

Dim Variable_Name

If you have a number of variables to declare, you can do this on the same line by separating them with commas, as in the following Dim statement:

Dim intRefNo, intAnyVar

As you start to write more and more complex scripts, you can reduce the number of bugs by referring back to the Dim statements to check the spelling of the variables you are using. Many bugs have been found to be simple typos of a variable name. Try the simple WSH script in Example 3-4 exactly as it's written (including the deliberate mistake). Enter a value into the input box and check the result.

Example 3-4. A typo in a variable name

Dim tstVar1 tstVar1 = InputBox("Enter a value") MsgBox testVar1

Interesting result, isn't it? No matter what you type into the input box, the message box is always blank. Now in this small script, it's pretty noticeable that we misspelled the name of the variable, and that VBScript treats tstVar1 and testVar1 as two different variables altogether. However, more complicated scripts won't bear out this error so easily. We know many frustrated programmers who have tracked down significant logic errors to misspelled variable names. Don't despair, though VBScript has a tool for helping us to eliminate this problem.

3.2.5.1 Option Explicit

Make a very slight amendment to the script shown in Example 3-4: add the statement Option Explicit on a line directly before the Dim statement. Run the script again, with the mistake still there. Now, instead of getting a useless empty text box that gives us no clue why our script didn't work, we get the error message, "Variable is undefined." We now know what we are looking for: the message tells us that we haven't declared a variable, and gives us the line number on which the error occurred. Even in a complex script, it usually takes only a couple of seconds to find and correct the bug.

Using Option Explicit is good programming practice. It forces us to declare all variables with Dim, and, should we make an error in the script, makes it easier to find.

3.2.6 Array Variables

The variables we have dealt with so far have contained single values, or, to give them their correct title, are scalar variables. But there are many occasions when you need to assign a range of values to a single variable. This type of variable is called an array. Arrays allow us to store a range of values in memory, each of which can be accessed quickly and efficiently by referring to its position within the array. You can think of an array as a very simple database of values. Arrays can hold all data types supported by VBScript.

Before examining arrays in VBScript in detail, let's quickly cover some of the terminology used when talking about arrays. Creating an array is called dimensioning (i.e., defining its size). The individual data items within the array are known as elements, and the reference number we use to access these elements is known as an index. The lowest and highest index numbers are known as bounds or boundaries. There are four main types of arrays; arrays can be either fixed or dynamic; arrays can also be either one-dimensional or multidimensional.

3.2.6.1 Fixed arrays

Most of the time, we know how many values we need to store in an array in advance. We can therefore dimension it to the appropriate size, or number of elements, prior to accessing it by using a Dim statement like the following:

Dim myArray(5)

This line of code creates an array, named myArray, with six elements. Why six? All VBScript arrays start with location 0, so this Dim statement creates an array whose locations range from myArray(0)to myArray(5).

Example 3-5 contains a simple WSH script that illustrates a fixed array. The script begins by instructing the VBScript engine to check that all our variables are correctly declared, then uses the Dim statement to dimension iArray as an array containing six elements, with indexes ranging from 0 to 5, as well as to dimension three other variables. The next six lines of code populate the array with values by explicitly assigning a value to each array element. This entire process of declaring and populating the array is done outside of a defined subroutine, which means that iArray is available to all subroutines and functions on the page (if there were any). This is known as scope, which we cover in depth later in this chapter.

Example 3-5. Using a fixed array

Option Explicit Dim sNumber, iNumber, iElement Dim iArray(5) iArray(0) = 12 iArray(1) = 3 iArray(2) = 13 iArray(3) = 64 iArray(4) = 245 iArray(5) = 75 sNumber = InputBox("Enter a number between 0 and 5", _ "Fixed Array", "0") If Not IsNumeric(sNumber) Then MsgBox "Invalid string entry" Else iElement = iArray(sNumber) MsgBox iElement End If

When we enter a number into the text box and click the button, the routine makes sure that our entry can be converted to a number; if not, it displays an error dialog. Otherwise, a message box containing the value of the array element whose index we entered is displayed. Note that, in this case, VBScript is able to automatically convert the string that we entered using the InputBox function into an integer used as the array index. If it hadn't been able to do this, or if we had chosen to handle the conversion ourselves, we could have used the CInt function.

Being the inquisitive type, you've probably already entered a number greater than 5 or less than 0 just to see what happens, right? You get an error message, "Subscript out of range." The subscript is the index number, and in a real application, we'd have checked that the number entered was within the limits or bounds of the array prior to using the number. We'll see how this is done in Section 3.2.6.3 later in this chapter.

Fixed arrays are fine when we know in advance how many values or elements we need. But there are many cases where we do not have prior knowledge of this, and we need a way to expand our array should we have to. We can do this by declaring and using a dynamic array.

3.2.6.2 Dynamic arrays

The most convenient uses of an array are to store input from the user and to allow the user to input as many items of data as they like. Our application therefore has no way of knowing how to dimension the array beforehand. This type of problem calls for a dynamic array. Dynamic arrays allow you to expand the number of array elements by using the ReDim statement to redimension the array while the program is running.

A dynamic array is declared by leaving out the number of elements, like this:

Dim myDynamicArray( )

When you need to resize the array, use the ReDim keyword:

ReDim myDynamicArray(10)

You can also declare a dynamic array, and specify the initial number of elements at the same time, using ReDim:

ReDim anyDynamicArray(4)

To populate an array with a series of values, you can use the intrinsicArray function. The function allows you to quickly assign a range of comma-delimited values to an array. For instance, assigning values to the array in Example 3-6 with the Array function would be quite easy.

Dim myArray myArray = Array(12,3,13,64,245,75)

To use the Array function, simply declare a variable, then assign the values of the array to the variable using the Array function. Any data type (even mixed data types) can be used with the Array function, as the ASP page in Example 3-5 shows.

There is no limit to the number of times you can redimension a dynamic array, but obviously messing around with variables in this way carries an element of risk. As soon as you redimension an array, the data contained within it is lost. Don't panic. If you need to keep the data, use the Preserve keyword:

ReDim Preserve myDynamicArray(10)

In fact, ReDim creates a new array (hence its emptiness). Preserve copies the data from the old array into the new array. This means that redimensioning arrays using the Preserve keyword results in poor performance for large arrays or for arrays with elements that have long strings. Another important point to note is that if you resize an array by contracting it, you lose the data in the deleted array elements.

Example 3-6. Using the array function

 

Using the Array Function

<% ShowArray %>

Example 3-7 contains a client-side script that shows how to use a dynamic array to save multiple inputs from the user. When the user clicks the "Add to array" button, the contents of the text box are added to myArray, an array that is dynamically resized beforehand. When the user clicks the Show Array Contents button, a dialog box like the one shown in Figure 3-1 displays the data stored to the array.

Figure 3-1. The contents of our dynamic array

Example 3-7. Using dynamic arrays

 

Dynamic Array Application

Because the HTML text box controls return string data, you can save any type of data in your array, but they will automatically be saved as strings. This means that you must remember to convert the data saved in arrays before using them in calculations. This in turn requires that you check to make sure that data is actually numeric before accepting it or using it.

The previous example is fine as it stands, except that, as you can see from the source code, we have to keep track of the size of the array by using the intIndex variable. But VBScript allows a much cleaner approach to the problem of finding out how many elements there are in the array.

3.2.6.3 Determining array boundaries: UBound and LBound

The UBound and LBound functions can be used to find the lower index and the upper index, respectively, of an array. UBound can be put to good use: to find the current size of a dynamic array.

VBScript and the Option Base Statement

In VB and VBA, you can use the Option Base statement to define the initial position of an array. The Option Base statement, however, is not supported by VBScript. All VBScript arrays begin at position zero. But note that an ActiveX component created with Visual Basic can return an array with a nonzero lower bound to a VBScript script.

The syntax for UBound is:

x = UBound(arrayname)

UBound returns the highest index number of an array. This is always one less than the actual number of elements in the array, unless the array was returned to the script by a Visual Basic component and has had its lower bound set to a non-zero value. For example, if myArray has ten elements, Ubound(myArray) returns the number nine. So we determine the total number of elements in an array as follows:

myArraySize = UBound(array) + 1

To illustrate the use of UBound, let's rewrite parts of the dynamic array program in Example 3-7, as shown in Example 3-8. Instead of using an integer variable like intIndex in Example 3-7 to continually track the size of the dynamic array, Example 3-8 uses the UBound function.

Example 3-8. The UBound function

 

Dynamic Array Application No.2

The arrays that we have looked at so far are termedsingle-dimension arrays. They hold one element of data in each index location, which is fine for most needs. However there are times when you need to hold a full set of data for each element. These are called multidimensional arrays.

3.2.6.4 Multidimensional arrays

To get a sense of when using multidimensional arrays is appropriate, let's look at two situations in which our scripts benefit from using arrays. First, there's the simple case of the single-dimension array. Let's say we're an importer putting together an application that will display to a user the country of origin of our company's products when they click a button. We can use a single-dimension array to hold the data in this case, a string containing the country of origin. We have one piece of data for each element, as follows:

Element number

Data

0

Product 1 Country of Origin

1

Product 2 Country of Origin

2

Product 3 Country of Origin

Then the marketing department suggests that the application be "improved." Instead of just showing the country of origin of each product, they also want to show its weight and any potential shipping hazard. If we continue to use a single dimension array, this poses something of a problem, as we can see from the following table.

Element number

Data

0

Product 1 Country of Origin

1

Product 1 Weight

2

Product 1 Hazards

3

Product 2 Country of Origin

4

Product 2 Weight

5

Product 2 Hazards

6

Product 3 Country of Origin

7

Product 3 Weight

8

Product 3 Hazards

etc.

 

As you can see, there is no structure to this data; it's all held sequentially, and as a result, can be very difficult to access. The solution is to use a multidimensional array. A multidimensional array allows you to have a separate array of data for each element of your array. Therefore, each element of the array in turn contains an array. To continue our product importer example, let's say that we have four products, and for each product we want to store three items of data. We define the multidimensional array as follows:

Dim ourProductData(3,2)

VBScript and User Defined Structures

If you're an experienced VB or VBA programmer, you might prefer another solution an array of user-defined structures to a multidimensional array. However, this solution is not available with VBScript. VBScript does not support the Type...End Type construct, and therefore does not allow you to define a structured data type.

This is the equivalent of the following data table, which consists of four rows and three columns. Each data cell of the table can therefore be viewed as a coordinate, with the first cell (the one containing product 1's country of origin) starting at 0,0. The row number defines the first value of the coordinate, while the column number defines the second:

 

Country of origin

Weight

Hazards

Product 1

Element (0,0)

 

Element (0,2)

Product 2

     

Product 3

     

Product 4

Element (0,0)

 

Element (0,2)

Multidimensional arrays can contain up to 60 dimensions, though it is extremely rare to use more than two or three dimensions.

Figures Figure 3-2 and Figure 3-3 illustrate the difference between a one-dimensional array and a multidimensional array in this case, with a two-dimensional array. Notice how the two-dimensional array can be thought of as a one-dimensional array (the top row) with each element having its own individual array dropping down from it to form a column.

Figure 3-2. A one-dimensional array

Figure 3-3. A two-dimensional array

If in our sample ASP application, which is shown in Example 3-9, we set ourselves a rule that the country of origin will always be in element 0, the weight in element 1, etc., then we have a method by which we can quickly access each individual element of data. So if we need to access the weight for product 3, we use the following line of code:

strDataString = strShippingData(2,1) ' row #3 column #2

Because we know that the weight will always be in column two, we can use a constant to help the readability of the code something known as self-commenting code. This is an ideal job for a constant, as the following code fragment shows:

Const weight = 1 strDataString = strShippingData(2, weight)

In this case, the most important part of creating our ASP application occurs before we actually begin writing our script, when we decide how we want to structure our multidimensional array.

Once that is done, implementing the goal for which the ASP page is created to display shipping information about a selected product is fairly straightforward, as shown in Example 3-9. The ASP page can display a simple list of products, or it can display a list of products along with information about one product whose hyperlink the user has clicked. Since the user clicks any of four hyperlinks to display shipping information about a particular product, a single routine can handle the display of information, as long as it knows which "row" of the multidimensional array contains that product's information; that routine is named ProductInfo. The HREF attribute of each product's tag includes a query string consisting of the Product element and its value, which is the index of the product's information in the strShippingData array. This index value is then passed as an argument to the ProductInfo routine if the user has clicked on a product hyperlink. The ProductInfo routine then simply retrieves the value of each element in the subarray belonging to the designated row and displays it to the web page. The result resembles Figure 3-4.

Example 3-9. Using a multidimensional array

 

Product Shipping Data<% 'declare the constants Const country = 0 Const weight = 1 Const hazards = 2 Dim strShippingData(3,2) ' declare a multidimensional array 'assign values to the array strShippingData(0, country) = "Made in Finland" strShippingData(1, country) = "Made in Malawi" strShippingData(2, country) = "Made in USA" strShippingData(3, country) = "Made in Outer Mongolia" strShippingData(0,weight) = "Weight = 34 Kilos" strShippingData(1,weight) = "Weight = 17 Kilos" strShippingData(2,weight) = "Weight = 10 Kilos" strShippingData(3,weight) = "Weight = 15 Kilos" strShippingData(0,weight) = "No Hazard" strShippingData(1,hazards) = "Highly Inflammable" strShippingData(2,hazards) = "No Hazard" strShippingData(3,hazards) = "Highly Inflammable" %> <% Dim iCtr For iCtr = 0 to 3 %> <a href="MultiDim.asp?Product=<%=iCtr"> > Product <%=iCtr + 1 %></a>

<% If Request.QueryString.Count > 0 Then If CInt(Request.QueryString("Product")) = iCtr Then ProductInfo CInt(Request.QueryString("Product")) End If End If Response.Write "

" Next %>

Figure 3-4. Sample output from Example 3-9

You can use a multidimensional array as a rudimentary database that is located within the client machine's memory. When you access a particular element of a multidimensional array, the value of the first dimension indicates a particular record of your database, while the value of the second dimension designates a particular field belonging to that record.

3.2.6.5 Dynamic multidimensional arrays

Earlier, you saw how a one-dimensional dynamic array can be resized while your program is executing. Multidimensional arrays can be dynamic, too (as shown in Example 3-10), and the rules for redimensioning them are similar, but since you have more than one dimension to think about, you have to take care how you use and redimension them. The rules for using a dynamic multidimensional array are:

Example 3-10. Redimensioning a two-dimensional array

Dim myArray( ), nDims, iSelection iSelection = vbYes Do While iSelection <> vbCancel iSelection = MsgBox("Create 2 dimension array?", _ vbQuestion Or vbYesNoCancel, "Dynamic Arrays") If iSelection = vbYes Then ReDim myArray(10,5) nDims = 2 ElseIf iSelection = vbNo Then ReDim myArray(4,10,2) nDims = 3 End If If iSelection <> vbCancel Then MsgBox "The upper bound of dimension " & nDims & _ " is " & UBound(myArray, nDims) End If Loop

3.2.6.6 Using UBound with multidimensional arrays

As you saw earlier, the UBound function returns the highest subscript (element number) in an arraythat is, its Upper Boundary. You can also use UBound with a multidimensional array, except to find the largest element of a multidimensional array, you need to also specify a dimension:

largestElement = UBound( arrayname , dimensionNo )

To sum up, use fixed arrays to hold predetermined blocks of data in memory. If you don't know the precise size of an array prior to defining it, use a dynamic array. Finally, if you need to reference more than one data field per data item, use a multidimensional array.

We have now covered the basics of variables and constants, apart from one major issue. You may have noticed in some of the previous examples that some variables and constants were declared at the very beginning of the script, outside of any subroutines, while some were declared within particular subroutines. Precisely where in a program or script you declare a variable or constant determines its scope and its lifetime.

3.2.7 Scope and Visibility

A variable's scope determines where within a script you are able to access that particular variable and whether that variable is visible within a particular routine. In a nutshell, variables declared outside of subroutines and functions can be accessed by the whole script, while those declared within a subroutine or function can be accessed only in the procedure in which they've been declared.

Global Scope

A variable has global scope when it can be accessed by all the subroutines and functions contained in a particular script. Variables and constants that have global scope also reside in memory for the lifetime of the script. That is to say, as long as the script remains in memory, its global variables and constants also remain in memory. To create a variable with global scope, you must declare it outside of any subroutine or function.

3.2.7.1 Global scope

Example 3-11demonstrates the use of global variables and constants in a WSH script. Since lngMyVar is defined outside of any of the script's procedures, it is a global variable that is visible to all routines. This is apparent from the GetUserInput procedure, which prompts the user to assign a value to lngMyVar and then calls the MySecondProcedure subroutine. MySecondProcedure displays a message box showing the value of lngMyVar, even though lngMyVar was not passed as a formal parameter to the procedure. (For a discussion of passing parameters, see Chapter 2.) If lngMyVar were not visible throughout the script, GetUserInput would not have been able to assign a value to lngMyVar, and the MySecondProcedure routine would not have been able to access that value.

The IncrementValue procedure illustrates the use of a global constant. Because MY_CONST is defined and assigned a value outside of a function or procedure, it is visible to IncrementValue, which adds it to the value that the user entered in the input box and assigns the result back to lngMyVar.

Example 3-11. Global scope

Option Explicit 'any variable or constant declared here will be available to 'all scripts in the document Dim lngMyVar Const my_Const=5 GetUserInput( ) 'use lngMyVar in unrelated procedures just to check whether it's global MySecondProcedure IncrementValue MySecondProcedure MultiplyConstant MySecondProcedure Sub GetUserInput( ) 'lngMyVar does not need to be declared here - it's global lngMyVar = InputBox("Enter a Number: ", "Script-Level", 0) End Sub Sub MySecondProcedure( ) 'display the value of lngMyVar MsgBox "lngMyVar: " & lngMyVar End Sub Sub IncrementValue 'let's add the value of the global constant to lngMyVar lngMyVar = lngMyVar + my_Const End Sub Sub MultiplyConstant lngMyVar = lngMyVar + (my_Const * 2) End Sub

One peculiarity of this script is worth noting: in addition to including global constant and variable declarations in this WSH script, we have also included global executable code. InWSH,Outlook forms, and Internet Explorer, assignments and other executable code statements that are stored globally are executed. In Internet Explorer, you can include multiple