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.
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
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:
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
arto 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.
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
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.