Published: Tuesday, March 28, 2000
Variables and Values in VBScript
By Bill Wilkinson
| Introduction |
|
One of the most used but least understood features of VBScript is the flexibility
of variables and values as used throughout the language. This short series of
articles will hopefully remove some of the mysteries of VBScript for you.
In this first article, we will explore the basic principles of variables and values.
In succeeding articles, we will discuss arrays, user-defined objects, and more.
The second part, Variables, Values, and Arrays in VBScript,
examines how VBScript handles single and multi-dimensional arrays.
Finally, the third part, Object References in VBScript,
looks at object references and how VBScript handles copies of objects and arrays.
|
Introduction to Variants:
If you are a C or C++ programmer experienced in COM and OLE, you will hopefully know
what I mean when I say that every variable and every value (except certain
intermediate values) in VBScript is actually an instance of an OLE VARIANT type. If
you don't know what that means, read on.
To begin, let's talk about what variables look like in most other languages. In C
and C++ and Java and Pascal and even Visual Basic, you typically tell the language
processor (compiler or interpreter) what kind or type of variable you are creating.
For example, you would do the following to create a variable named myNumber
that is capable of holding values from roughly -2,000,000,000 to
+2,000,000,000 in these various languages (although the actual range may
depend on the particular compiler you are using):
- C/C++/Java:
int myNumber;
- Visual Basic:
Dim myNumber AS Long
- Pascal:
myNumber : Integer;
But in VBScript, all variables are always of the same kind or type, the
aforementioned VARIANT type. And just what is a VARIANT? Ahhh…
A VARIANT is a special kind of data structure that is capable of holding or
referring to any kind of data that OLE (or VBScript) understands! And what it holds
can vary, from moment to moment! Actually, you may have seen this in VBScript code,
such as:
<%
uDate = Request.Form("userDate")
uDate = CDate( uDate )
%>
|
If you didn't already know it, be aware that Request.Form("fieldname")
and Request.QueryString("fieldname") always return a string!
This only makes sense: The browser certainly doesn't know the intended use of any
given form field, so it always sends all data on to the server as a string. And
just because a string contains 17 November 2001 doesn't mean, to the
server, that it is necessarily a date. So, if you want to ensure that a given form
field contained a date - or if you need to do datewise manipulation of a value from
such a field - you use the CDate function. So that same variable first
held a string and then held a date/time value! This would be impossible with the
built-in data types found in most other languages.
How does it work?
Inside your computer's CPU (presumably, a Pentium processor, unless you are lucky
enough to be running ChiliSoft ASP on Solaris
or AIX?), there are certain data types that it understands in ways that are built
into its hardware. Because these are so fundamental to computer processing, they are
sometimes called "primitive" types. When a primitive type appears in your computer's
memory (in RAM or ROM or even on a disk), it occupies a certain number of bytes,
which number is fixed for each primitive type.
Examples: A C/C++/Java int (VB Long, Pascal Integer,
as shown above) always occupies four (4) bytes of memory. A short format floating point
number (which can represent numbers with a decimal point with roughly 6 or 7 digit
accuracy) also uses four bytes. A long format floating point number (also known as
a "double", having roughly 14 or 15 digits of precision) needs 8 bytes. Various
other primitive types occupy from one to eight bytes of memory. (Theoretically, a
boolean needs only one bit of memory, but in practice most computer languages use one
or more bytes because that fits the computer CPU architecture better.)
In the "conventional" languages, then, when you create a variable of a particular type
(as in the various integer examples, above), that variable is always exactly that
size. You can't store a double in a variable that was allocated as an
integer (or vice versa—even though the 4-byte integer would fit in the
8 byte double, the languages don't allow it for reasons too complex to go into here).
But then there is VARIANT. If you happen to know Pascal, you might recognize a VARIANT
as simply a "varying record." C and C++ don't have any built-in type that
corresponds (and you really can't do this in Java, at all), but sometimes you might
hear the term "discriminated union" used to describe this kind of structure.
Briefly, a VARIANT always occupies 16 bytes of memory but only uses what is
needed. And the first two bytes of the VARIANT always indicate what the other 14 bytes
are holding!
So if you do something in VB like this:
The variable num will have its first two bytes set to the number 2 (indicating a
short integer) and two other bytes of the 16 (a particular two—and which two of the
16 never changes, but we don't care which two for this discussion) will hold the
integer number 731. If you do:
then the first two bytes of num will contain the number 3 and a particular four bytes
of the 16 will contain the long integer value 12345678. If you are curious about
what all the possible values of those first two bytes can be with VBScript, then
look at the documentation in the VBScript reference manual for the
VarType function, where all the values are listed (view
the technical docs).
(Not relevant to
this discussion, but of interest to C/C++ programmers, perhaps: There are many more
possible values for those two bytes within the definition of an OLE VARIANT data
type. But VBScript uses only the values noted under the documentation for
VarType.)
So now we can understand how the code we looked at above works:
<%
uDate = Request.Form("userDate")
uDate = CDate( uDate )
%>
|
The first assignment to the variable uDate will set its first two bytes
to 8, indicating that the VARIANT contains a string. The second assignment changes that
number to a 7, indicating that the variable now contains a Date/Time value. And, in
the process, the other bytes of the VARIANT are changed as needed.
"But wait," I can hear you say, "if I have a string of 100 characters how do they
all fit into those 16 bytes of the VARIANT?" Ahhh…you knew there had to be trick in
here! And the trick is simple: For all except the primitive data types (look above
to see what they are), the VARIANT contains a pointer to the actual data! So if
you look at the list of type numbers in the documentation
for VarType, you will hopefully understand that the following numbers do
not represent primitive types and so the rest of the VARIANT will contain a pointer
to the actual data:
VarType Values that Use Pointers |
8 | vbString | A pointer to the string contents |
9 | vbObject | A pointer to an ActiveX object |
10 | vbError | A pointer to an Error object |
12 | vbVariant | Please don't ask about this one yet! |
13 | vbDataObject | A DAO object (may not be used in ASP?) |
8192 | vbArray | An array |
Looking again at the uDate function example, above, we can see that a
given variable can sometimes hold a VARIANT that contains a primitive value and
sometimes one that contains a pointer to some more extended data. Truly, VBScript variables,
through the mechanism of the VARIANT, are extremely flexible.
And now, before we leave this subject for this week, let's look at an interesting
little ASP page:
<HTML><BODY>
<%
Set d1 = Server.CreateObject("Scripting.Dictionary")
d1.Add "first", "added via d1.add"
Set d2 = d1
d2.Add "second", "this via d2.add"
Response.Write "from d1(second) we get: " & d1("second") & "<P>"
Response.Write "from d2(first) we get: " & d2("first") & "<P>"
%>
</BODY><HTML>
|
I won't make you actually try that code, though I do encourage you to do so. And
even experiment with it some. But to save you time, here is what that page looks
like in a browser:
from d1(second) we get: this via d2.add
from d2(first) we get: added via d1.add
Do you understand the implications of that? The "objects" referenced by the
variables d1 and d2 are actually one and the same object!
So doing:
did not copy the object referenced by d1. Instead, only the pointer
that d1 contains is copied to a pointer in d2. The actual
object does not move, is not affected by the copy, and remains fully accessible to
both variables.
Start considering the implications of that seemingly simple action. And then next
time we can discuss how this relates to other features of VBScript and start
discussing how arrays work.
Happy Programming!
By Bill Wilkinson