The JScript Type System, Part Six: Even more on arrays in JScript .NET

The JScript Type System, Part Six: Even more on arrays in JScript .NET

  • Comments 5

You might have noticed something odd about that last example using SetValue. If you actually look up the method signature of SetValue in the CLR documentation it notes that the function signature is:

 

public function SetValue(value : Object, indices : int[]) : void

 

The odd thing is the annotation on indices. It is typed as taking a .NET array of integers but in the example in my last entry we give it a literal JScript array, not a hard-typed CLR array.

 

JScript .NET arrays and hard-typed CLR arrays work together, but because these two kinds of arrays are so different they do not work together perfectly. The problem is essentially that JScript .NET arrays are much more dynamic than CLR arrays. JScript .NET arrays can change size, can have elements of any type, and so on.

 

The rules for when JScript .NET arrays and CLR arrays may be used in place of each other are not particularly complicated but still you should exercise caution when doing so. In particular, when you use a JScript .NET array in a context where a CLR array is expected you can get unexpected results. Consider this example:

 

function ChangeArray(arr : int[]) : void

{

  print(arr[0]); // 10

  arr[0] += 100;

}

var jsarr : Array = new Array(10, 20, 30);

ChangeArray(jsarr);

print(jsarr[0]); // 10 or 110?

 

This might look like it prints out 10 then 110, but in fact it prints out 10 twice. The compiler is unable to turn the dynamic JScript array into a hard-typed array of integers so it does the next best thing. It makes a copy of the JScript array and passes the copy to the function. If the function reads the array then it gets the correct values. If it writes it, then only the copy is updated, not the original.

 

To warn you about this possibly unintentional consequence of mixing array flavours, the compiler issues the following warning if you do that:

 

warning JS1215: Converting a JScript Array to a System.Array results in a memory allocation and an array copy

 

You may now be wondering then why the call to SetValue which had the literal JScript .NET array did not prompt this warning. The warning is suppressed for literal arrays. In the case of literal arrays the compiler can determine that a literal array is being assigned to a CLR array type. The compiler then optimizes away the creation of the JScript .NET array and generates code to create and initialize the CLR array directly. Since there is then no performance impact or unexpected copy, there is no need for a warning.

 

Note that if every element of the source JScript .NET array cannot be coerced to the type of the hard-typed CLR array then a type mismatch error will be the result. For instance, if you tried to coerce an array containing strings to an array of integers then this would fail:

 

var arr1 : int[] = new Array(10, "hello", 20); // Type mismatch error at runtime

var arr2 : int[] = [10, "hello", 20];          // Type mismatch error at compile time 

 

Note also that this applies to multidimensional arrays. There is no syntax for initializing a multidimensional array in JScript .NET:

 

var mdarr : int[,] = [ [ 1, 2 ], [3, 4] ]; // Nice try, but illegal

 

A rectangular multidimensional array is not an array of arrays. In this case you are assigning a one-dimensional array which happens to contain arrays to a two-dimensional array of integers. That is not a legal assignment. If, however, you want a ragged hard-typed array it is perfectly legal to do this:

 

var ragged : int[][] = [ [ 1, 2 ], [3, 4] ];

print(ragged[1][1]); // 4

 

Rectangular multidimensional arrays are indexed with a comma-separated list inside one set of square brackets. If you use ragged arrays to simulate true multidimensional arrays then the indices each get their own set of brackets.

 

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.  

 

Next time I'll talk a bit about going the other way -- using a CLR array where a JScript array is expected.

  • > 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. I wonder whether you meant to say here that JScript .NET arrays *have* CLR array fields? This paragraph sounds rather confusing to me...
  • I found this post very interesting. Recently I've added a new module to BeyondJS called BeyondRhino, targeted at the Rhino platform. One of the features this module provides is better interop between JavaScript types and Java types, including arrays and collections. I also wanted to make it easier to convert between JavaScript and Java arrays. Since I couldn't modify the behavior of the JavaScript interpreter to automatically convert between array types, I needed to take a more explicit route (well, technically I could modify the behavior since Rhino is open source, but I must admit I'm not feeling quit up to that task right now). My solution was to add a .toJava() method on all JavaScript basic types including arrays. Likewise I added a toJavaScript() function to convert Java arrays to JavaScript arrays. For example: var a = [1,2,3].toJava(); a is now a Java array of integers (type [I...). You can also pass arguments to the toJava() method to control the type of array generated. The only upside of this technique when compared to what you did with JScript.NET is that it makes it clearer IMO that what you get is a copy of the original array. OTOH I also added methods to JavaScript arrays that allow access and manipulation of the array object itself via Java's collection interfaces. For example: var a = [1,2,3]; var l = a.list(); returns an List interface on top of the specific array instance. So you can use it to manipulate that instance: l.add(4); for ( var i in a ) print(a[i] + " "); // outputs 1 2 3 4 Given the highly dynamic structure of JavaScript arrays, it seems to make a lot of sense to enable their use as generalized collection objects. BTW the reason for this work is that I want to enable the use of JavaScript as a UnitTesting platform for Java.
  • > Given the highly dynamic structure of JavaScript arrays, it seems to make a lot of sense to enable their use as generalized collection objects. Indeed! > I want to enable the use of JavaScript as a UnitTesting platform for Java. That's a cool idea, but wouldn't it be on the face of it easier to use Java as a unit testing platform for Java, rather than making Rhino interoperate better with Java? :-)
  • > but wouldn't it be on the face of it easier to use Java as a unit testing platform for Java, rather than making Rhino interoperate better with Java? Maybe, but it wouldn't be as fun :-D There are a couple of advantages in using a language like JavaScript over standard Java: 1. Rhino provides an interactive environment, so I can test classes interactively. 2. It's easier to construct some data structures using JavaScript than it is using Java. For example, if I want to create a collection containing numbers 1 through 10 that exposes the List interface. All I need to do using BeyondJS is write: (1).to(10).list() Consider the alternative Java code. 3. If you look through the Rhino samples you'll see that it's also easier to create event handlers than in Java. BTW, It's not necessarily a putdown of Java to claim that JavaScript may be a better PL for constructing tests than Java. Writing tests, especially dynamic tests, is not the same as writing standard apps. A lot of people are using things like Jython for testing Java, there is even a new PL being design specifically for this purpose: http://groovy.codehaus.org/ There is one significant disadvantage in using Rhino: the Rhino interactive environment doesn't do code completion or argument tips. But you can use the standard JavaScript facilities to do introspection on Java objects.
  • Wouldn't it just be better to use the real version of javascript instead of jscript which is riddled with problems?

    Or for that matter instead of trying to hack code for .Net use sun's ver of Java + IDE?

    It has been my experiance that trying to hack code to try and get it to work differently than it does originally is a bad idea since it is pretty much unsupported by design.
Page 1 of 1 (5 items)