The JScript Type System Part Seven: Yeah, you’ve probably guessed that I wrote the array stuff

A reader asked me to clarify a point made in an earlier entry:

Note that JScript .NET arrays do not have any of the methods or properties of a CLR array. (Strings, by contract, can be used implicitly as either JScript .NET strings or as System.String values, which I’ll talk more about later.) But JScript .NET arrays do not have CLR array fields like Rank, SetValue, and so on.

When you have a string in a JScript .NET program, we allow you to treat it as both a System.String and as a JScript object with the String prototype.  For example:

var s = "   hello   ";
print(s.toUpperCase());
// calls JScript string prototype's toUpperCase
print(s.Trim());
// calls System.String.Trim

Which is it really?  From a theoretical standpoint, it doesn’t really matter — you can use it as either.  From an implementation standpoint, of course we use System.String internally and magic up the prototype instance when we need one — just as in JScript classic all strings are VT_BSTR variants internally and we magic up a wrapper when we need one.  JScript .NET strings and CLR strings really are totally interoperable.

Arrays aren’t quite so seamless.  

When you try to use a JScript .NET array when a CLR array is expected, we create a copy.  But when you go the other way, things are a little different. Rather than producing a copy, using a CLR array as a JScript .NET array “wraps it up”. No copy is made. The operation is therefore efficient and preserves identity. Changes made to a wrapped array are preserved:

function
ChangeArray(arr : Array) : void {
  print(arr[0]); // 10
  arr[0] += 100;
  // JScript .NET methods work just fine
  print(arr.join(":")); // 10:20:30
}

var arr : int[] = [10, 20, 30];
ChangeArray(arr);
print(arr[0]); // 110

The principal rule for treating a CLR array as a JScript .NET array is that it must be single-dimensional. Since all JScript .NET arrays are single-dimensional it makes no sense to wrap up a high-rank CLR array.

Once the array is wrapped up it still has all the restrictions that a normal hard-typed array has. It may not change size, for instance. This means that an attempt to call certain members of the JScript .NET Array prototype on a wrapped array will fail. All calls to push, pop, shift, unshift and concat as well as some calls to splice will change the length of the array and are therefore illegal on wrapped CLR arrays.

Note that you may use the other JScript .NET array prototype methods on any hard-typed array (but not vice versa). You can think of this as implicitly creating a wrapper around the CLR array, much as a wrapper is implicitly created when calling methods on numbers, Booleans or strings:

var arr : int[] = [10, 20, 30];
arr.reverse();    
// You may call JScript .NET methods on hard-typed arrays
print(arr.join(":"));   // 30:20:10

There might be a situation where you do want to make a copy of a CLR array rather than wrapping it. JScript .NET has syntax for this, namely:

var sysarr: int[] = [10, 20, 30];
var jsarr1 : Array = sysarr; 
// create wrapper without copy
var jsarr2 : Array = Array(sysarr); 
// create wrapper without copy
var jsarr3 : Array = new Array(sysarr); 
// not a wrapper; copies contents

In the last case jsarr3 is not a wrapper. It is a real JScript .NET array and may be resized.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s