Published: Wednesday, April 11, 2001
Variables, Values, and Arrays in VBScript (Part 2 of a 3-Part Series)
By Bill Wilkinson
| VBScript Under the Covers |
|
This article is Part 2 of a 3-Part article series by Bill Wilkinson.
Part 1 of this series, Variables and Values in VBScript,
examined how VBScript treated scalar variables: Strings and primitive data types. In this
part, Bill delves deeper under the covers and looks at how VBScript handles both single
and multi-dimensional arrays! Finally, in the third part, Object References in VBScript,
Bill looks at object references and how VBScript handles copies of objects and arrays!
|
Arrays in VBScript
In the previous article in this series we looked at
the basics of how variables and values are implemented in VBScript (and, with minor
variations, in JScript). In this second part of the series, we'll focus on how VBScript
represents and uses arrays.
As noted in the previous article, in VBScript all
variables are always of the same kind or type, a VARIANT (which is in turn an OLE-defined
structure). And a VARIANT instance always occupies 16 bytes of memory but only uses
what is needed. The first two bytes of the VARIANT always indicate what the other 14 bytes
are holding, and different types of data use pre-defined portions of those 14 bytes.
Enter, now, the array in VBScript. Much of this applies equally well to JScript, but there
are some details in the two languages that are different enough that we will limit this
discussion to VBScript, alone.
In conventional languages (C/C++/Java/Pascal/Fortran/many more), arrays are "homogeneous" and
the type of each element of the array is defined when the array is created. So if, in C/C++,
you did something like:
you would be allocating 100 integers, each occupying four bytes. But how is the space for
those integers allocated?
When you allocate an array, the system allocates contiguous memory sufficient to hold the
requisite number of items. Simple as that: 100 integers, four bytes each? Fine: 400 bytes
of memory all in one chunk.
The important part of this is that all elements of an array are always the same size.
Then, when you ask for a particular element in the array [say via x = arrayOfInt(76)],
the system simply multiplies the index [76 in the example] by the size of one item, adds that
number to the address of the start of the array, and presto! It is addressing the proper spot
in memory. In our example, 76 times four bytes per element is 304 bytes. We add 304 to
the address of the beginning of the array and we have the address of element 76.
But VBScript is a "typeless" language. Right? Any element of any array can hold any data
value. Right? So how does that work? How can the system know in advance how big each element
should be? Simple: As we noted in the first article and reiterated above, every value in
VBS is always an OLE VARIANT type! And that includes every element of every array! So every
element of a VBScript array is 16 bytes in size. So VBScript, too, allocates contiguous
memory for its arrays! And then we can just do the math, same as above, as needed.
So Dim ar(500) allocates 501 * 16 or 8016 bytes of memory.
"But, but, but..." you say, "what if I put a long string into each slot of the array?
8016 bytes might not even be enough to hold one of the strings, let alone 501 of them!"
Referring back to part 1 of this series: "For all except the primitive data types ... the
VARIANT contains a pointer to the actual data." The primitive data types are
Empty, Null, Integer, Long,
Single, Double, Date, Currency, and
Boolean. Every other kind of data-including strings-is non-primitive and is
represented in the variant by a pointer to the actual data.
A demonstration is in order:
<%
ar = Array("this","is","a","demonstration")
Response.Write ar(3)
%>
|
This is what happens:
- First of all, the system figures out that the array you are creating has size 4
(elements 0 through 3). So it allocates 4 times 16 bytes and points the variable
ar
to those 64 bytes.
- Then it allocates space for a string containing "this" and puts the address of
that string into slot 0 of the array; it sets the first two bytes of that slot to indicate
that the VARIANT points to a string.
- Then it allocates space for a string containing "is" and puts the address of that string
into slot 1 of the array; it sets the first two bytes of that slot to indicate that the
VARIANT points to a string.
- Then it allocates space for a string containing "a" and puts the address of that string
into slot 2 of the array; it sets the first two bytes of that slot to indicate that the
VARIANT points to a string.
- Then it allocates space for a string containing "demonstration" and puts the address of
that string into slot 3 of the array; it sets the first two bytes of that slot to indicate
that the VARIANT points to a string.
Whew. Okay?
NOW...a quiz: In that code, what does the variable named ar look like in memory?
Don't answer in haste. Think about it.
Did you remember part 1 of this series? Did you remember paragraph 2 of this article? To
quote: "all variables are always of the same kind or type."
Yes, even the variable ar is, of necessity, a VARIANT! And what do you suppose
its particular VARIANT contains? Yep. Two bytes that say it is a pointer to an array and
then, somewhere in the other 14 bytes, a pointer to the actual array!
So, in the next line of the code, above, we have the expression ar(3). And now
we understand how it works! The VBScript language processor retrieves the contents of the
variable ar. It looks at the VARIANT that is inevitably in those contents and
notes that this particular variant is a pointer to an array. So it picks up the address of
the array and remembers it. Then it sees the (3) as the element number [it would be an error
if ar were not an array!], so it multiplies 3 times 16. It thus adds 48 to the array address
it remembered to construct the address of element 3 of the array. Then it picks up the 16
bytes of memory that appear at the calculated address. Why 16 bytes? Because, again, every
element of the array is a VARIANT. It looks at the VARIANT it thus got and sees that this is
a string, so it extracts the address of the referenced string from the known spot in the
VARIANT, uses that address to go fetch the actual string, and (finally!) it can
Response.Write the string.
Wow! What a lot of work for a seemingly innocuous operation, right? Honest, this is
incredibly simple compared to what must happen when VBScript calls a method on some
ActiveX object. But let's not digress...
Now that we've looked at how VBScript handles single-dimensional arrays we should turn our
attention to multi-dimensional arrays. In Part 2
of this article we will examine how multi-dimensional (specifically two-dimensional) arrays
are internally managed by VBScript.
Read Part 2!