views:

354

answers:

4

This code is blunderous, as it adds a class to an array and later tries to pull it and manipulate it as if it were an object.

private function fail(event:Event):void
{
 var myObj:MyClass;
 var a:ArrayCollection = new ArrayCollection();
 var x:MyClass;
 var y:MyClass;

 myObj = new MyClass;
 a.addItem(myObj);
 a.addItem(MyClass);  // !!BAD!!

 x = a[0];
 y = a[1];
}

When I did this accidentally, it took me forever to see what I had done wrong. Partly because the error message didn't tell me anything I could understand:

TypeError: Error #1034: Type Coercion failed: cannot convert com.ibm.ITest::MyClass$ to com.ibm.ITest.MyClass.
    at ITest/fail()[C:\work_simple01\ITest\src\ITest.mxml:51]
    at ITest/___ITest_Button5_click()[C:\work_simple01\ITest\src\ITest.mxml:61]

So my question is, why is the line marked !!BAD!! above even allowed? I would expect a compile time error here. Since it compiles, there must be some use for this that I am unaware of. What is it?

+7  A: 

I assume the exception occurred at the last line of your sample, not the error you have flagged 'BAD'.

What you added to the array was the object that represented the class 'MyClass', not an instance of MyClass.

Being able to examine classes at runtime is a powerful feature and is the basis of the reflection features in .NET and Java. These features are often use to support extensibility patterns or implement serialization frameworks.

So manipulating one of these objects is a valid thing to do ... by it isn't an instance of MyClass, so you can't assign it to your y variable.

Rob Walker
A: 

The nice thing about late binding (and dynamic languages) is that it allows you a lot more flexibility in implementation. The downside is that the language doesn't protect you from making some simple mistakes that early binding and strong typing prevent. Personally, I'd look into using TDD (test driven development) as an aid to preventing these sorts of errors from creeping into your code.

tvanfosson
+7  A: 

The question seems to me to be equivalent to,"Why can I use a class as a value?" It's a good question.

There are two major things you can do with a class in ActionScript; you can instantiate it, and you can access static properites of it. (Okay, there are other things, but those are the obvious ones.) Instantiating a class is probably the most relevant use of a class as a value; the Class is its own factory, like ones you would make explicitly in C++ or Java.

Here's an example from a small Tetris game I was writing as an exercise. I had two classes, Brick and SceneBrick. A Brick was an in-game brick, the ones that fall and pile up. A SceneBrick was a brick just drawn in as the frame of the play area.

However, I used one function to draw both of them, without referring to either type within the function:

function drawBricks(xs:Array, ys:Array, brickType:Class){
 xs.map(function(o,i,a){
  var brick = new brickType();
  // etc.
 });    
}

And I could use that like this:

drawBricks([0,1,2,3], [4,4,4,4], Brick); // draw a long piece
drawBricks(times(0, 21), countFrom(0, 21), SceneBrick); // draw a big vertical "wall"

This is a very simple example, but I hope the point is clear - you can pass around a class and use it to instantiate that class, whereas in a language like Java or C++, you would have to either use it as a parameter for a generic class or define factory classes with some common supertype in order to do this.

Jesse Millikan
+1  A: 

It seems like in Flex, the collections don't specify the type of the values they should contain.

var a:ArrayCollection = new ArrayCollection();

So it feels logical to me that the compiler doesn't check the types of the values you add to it. Then assigning variables from collection elements can only be checked at runtime, since the compiler doesn't have the information.

As for classes being objects (and responding to messages), it is very convenient to build all kind of debugging / inspection / reflexion tools.

Sébastien RoccaSerra