суббота, 21 августа 2010 г.

Actionscript 3.0 type casting and type checking

Type casting and type checking have always been central to any computer programming language, especially in Object Oriented languages like Actionscript.
In fact, knowing what type of object you are receiving as a parameter or the ability to "transform" your object into another type so that you can pass it along to method calls and class properties are key to one of the most important concepts of Object Orientation:Polymorphism.
According to this principle, any object that extends from a certain hierarchical line (class inheritance or interface implementation) can be used in substitution of any of its ancestors. This results from the fact that descendants have the exact same external programmable interface as their ancestors (either implicitly by means of class inheritance, or by mandatory interface implementation).
Automatic type casting
Sometimes type casting occurs automatically. For instance if you set a property typed asObject with a DisplayObject (which is an Object's descendant), Flash automatically casts that DisplayObject to Object. In other words, whenever you use a descendant in place of one of its ancestors, it automatically is cast to that ancestor's type.
This doesn't mean, however, that the object ceased to be an instance of the descendant type. Only that, in that particular reference in a class property or method argument, it is known as being of the ancestor type. And it will carry that type whenever it is accessed through that property or argument. In other words, what determines the type of the object you are accessing is not the instance creation type, but the type of the property or parameter you're using to access it.
Explicit type casting
Since the object instance doesn't loose its creation type when being cast to an ancestor type, it may still be used whenever that descendant type is required. This is where it gets interesting: If you are trying to set a property of the descendant type using an instance created with that same type but stored in a variable of one of its ancestor types, Flash will complain about type incompatibility.
In order to be able to do this you'll have to explicitly cast the instance back to the descendant type. It sounds somewhat redundant that you have to cast an object to a type that you know it already is, but if you remember that what determines the type is not the instance but the variable used to access it, it makes perfect sense.
Actionscript provides two different techniques for type casting and one for type checking. For type casting your either use the cast operation or the as operator.
The cast operation
Performing a cast operation is very simple. You just have to surround the variable with parenthesis and prepend it with the class into which it's going to be cast.
var receivingVariable:DisplayObject = DisplayObject(objectReference);

The as operator
Using the as operator is equally simple. Just place it between the variable and the Class name like this:
var receivingVariable:DisplayObject = objectReference as DisplayObject;
If you're casting just to reach a property or method of the object you can still use the asoperator:
(objectReference as DisplayObject).alpha = 0;
Yet in this particular case, I would recommend the cast operation instead. I will explain why in a moment.
When casting objects bear in mind that it can fail due to a number of reasons that are beyond the scope of this post and involve concepts like type conversion and boxing.
Differences between the cast operation and the as operator
Both the cast operation and theas operator, when successful, have the same result. They return a reference to the target instance as being of the cast type.
They only differ in how they deal with failure to cast. The cast operation throws a runtimeTypeError if the cast fails, while the as operator returns a null value.
When should you use one or the other?
If you are absolutely certain that the cast will succeed, or if you are willing to surround each cast with a try catch statement or you don't mind your application throwing runtime errors all over, you can safely use the cast operation.
If, on the other hand, you prefer to be able to deal with cast errors elegantly without having to surround each one with a try catch, you should use the as operator.
I tend to prefer the as operator as it makes the code more readable (the cast operation can be confused with constructor invocation and type conversion operations) and is more in sync with the type checking is operator, which I'll present in a moment.
The only time when I absolutely favor the cast operation is when I'm only doing the cast to access a property or method of the object. The reason why I do this is because invoking a property or a method in a null value (returned by the as operator in case of cast failure) will throw a null reference runtime error instead of a type runtime error and as a best practice it is always best to get your errors right so that you don't end up chasing for them in the wrong places.
Type checking
Type checking can easily be done using the is operator in exactly the same way as the asoperator:
var test:Boolean = objectReference is DisplayObject;
The is operator returns a Boolean value stating whether the object is an instance of that type or interface or any of its ancestors.
It would be interesting to know if there are some impacts performance and memory wise when using any of these techniques and which would be best to get that last performance crunch you need. Maybe in a future post. Stay tuned to InsideRIA for updates

Комментариев нет: