On Vector and strong typing … though it will never happen to me, only to “the Other guy”

Consider the following simple class:

public class SomeCustomClass
{
	public var booleanProperty:Boolean;
	public var integerProperty:int;

	public function SomeCustomClass(integerProperty:int, booleanProperty:Boolean)
	{
		this.integerProperty = integerProperty;
		this.booleanProperty = booleanProperty;
	}
}

To instantiate an object of this class you will write a line similar to this:

var someInstance:SomeCustomClass = new SomeCustomClass(4, true);

If by any chance you will pass the parameters the other way around:

var someInstance:SomeCustomClass = new SomeCustomClass(true, 4);

Presumably the compiler is in STRICT MODE (which is Flash Builder’s default) and you will get a compile time error like:

1067: Implicit coercion of a value of type Boolean to an unrelated type int.

That is strong typing at work. You get an error because you passed in the wrong type. You go ahead an fix the error by changing the line of code to:

var someInstance:SomeCustomClass = new SomeCustomClass(4, 4);

Now the error is gone, but you still get an warning:

3590: int used where a Boolean value was expected.  The expression will be type coerced to Boolean.

You can fix it or just leave 4 in place and the code execute because 4 will be converted to true. Which may be ugly but “somehow” acceptable as long as your intention is to pass in the value true.

Enter the Vector class. The nice addition introduce with FP10.  Amongst the benefits listed in the docs there is type safety:

Type safety: in strict mode the compiler can identify data type errors. Examples of data type errors include assigning a value of the incorrect data type to a Vector or expecting the wrong data type when reading a value from a Vector. Note, however, that when using the push() method or unshift() method to add values to a Vector, the arguments’ data types are not checked at compile time. Instead, they are checked at run time.

The key issue here is the bold part of the statement. The Vector class constructor takes two arguments as follows:

Vector(length:uint = 0, fixed:Boolean = false)

If you want to create a fixed length vector you will invoke the constructor as follows:

var vect:Vector.<CustomClass> = new Vector.<CustomClass>(4, true);

Applying the same pattern of introducing error with SomeCustomClass  -Flash builder does not code-hint the Vector arguments Рyou might invert the arguments.

var vect:Vector.<CustomClass> = new Vector.<CustomClass>(true, 4).

Without strong typing, there is no compile type checking, so there will be no error or warning. The code will compile just fine and execute. Only that instead of a vector with 4 elements, a vector with 1 element will be created. To continue on this “conspiracy theory” path, let’s assume (for argument sake), that one is using the Socket class to connect to an endpoint, and wants to run several concurrent connections to cater for multiple ports of the same host. A factory method to create these connection based on host and an vector of ports may look like this:

public function createSocketConnections(host:String, portsVector:Vector.<int>):Vector.<Socket>
{
	var numPorts:int = portsVector.length;
	var connections:Vector.<Socket> = new Vector.<Socket>(true, numPorts);
	for (var i:int = 0; i < numPorts; ++i)
	{
 		connections[i] = new Socket(host, portsVector[i]);
	}

	return connections;
}

A simple call to invoke the method:

 var ports:Vector. = new [80, 8080, 2000];
var connections:Vector.<Socket> = createSocketConnections("172.10.0.1", ports);

And here is the lucky break, when running the code it yields a runtime error:

RangeError: Error #1125: The index 1 is out of range 1

Which gives more than enough to figure it out. Now let’s change the code just a little bit.

public function createSocketConnections(host:String, portsVector:Vector.<int>):Vector.<Socket>
{
	var numPorts:int = portsVector.length;
	var connections:Vector. = new Vector.(true, numPorts);
	for (var i:int = 0; i < connections.length; ++i)
	{
		connections[i] = new Socket(host, portsVector[i]);
	}

	return connections;
}

No error or warning, your code will perform just fine. However it will always create only one connection, configured with first port from the portsVector, and if – for any reason – that port will fail, the users won’t be able to connect anymore…

Instead of conclusion:

Since this paranoid scenario is not based on a true story, it will not happen to me or you, and not even to “the Other guy”… After all it is not so common to have a test server which takes requests only on a single port, under which scenario the code code always behaves properly. And is also not that common for a production production server to have more than port open …

So than this simple way to fail early:

[Test]
public function test_createSocketConnections():void
{
	var ports:Vector.<int> = new <int>[80, 8080, 2000];
	var connections:Vector. = createSocketConnections("172.10.0.1", ports);
	Assert.assertEquals("Number of sockets created ", ports.length, connections.length);
}

which fails the test with fails with the following error message:

Number of sockets created expected: 3  but was: 1

does not really make that much sense. Does it?

Leave a Reply

Your email address will not be published. Required fields are marked *

*