views:

716

answers:

5

From what I understand of ActionScript, there are two kinds of casts:

var bar0:Bar = someObj as Bar;  // "as" casting
var bar1:Bar = Bar(someObj); // "class name" casting (for want of a better name)

Also, and please correct me if I'm wrong here, as casting will either return an instance of the class or null, while "class name" casting will either return an instance of the class or raise an exception if the cast is impossible – other than this, they are identical.

Given this, though, as casting seems to be a massive violation of the fail-fast-fail-early principle... And I'm having trouble imagining a situation where it would be preferable to use an as cast rather than a class name cast (with, possibly, an instanceof thrown in there).

So, my question is: under what circumstances would it be preferable to use as casting?

+1  A: 

Use 'as' with arrays.

var badArray:Array;
badArray = Array(obj);

Will yield an array of length one with the original array in the first element. If you use 'as' as follows, you get the exptected result.

var goodArray:Array;
goodArray = obj as Array;

Generally, 'as' is preferable to 'Class()' in ActionScript as it behaves more like casting in other languages.

stevedbrown
When you say "other languages", which are you thinking of? I know for sure that Java will raise an exception if you try to perform a bad cast...
David Wolever
Java will convert a list properly if you do List list = (List<Integer>)obj;No exception, no problem. You do Array(obj) in AS, problem.
stevedbrown
+2  A: 

You need to use as to cast in two scenarios: casting to a Date, and casting to an Array.

For dates, a call to Date(xxx) behaves the same as new Date().toString().

For arrays, a call to Array(xxx) will create an Array with one element: xxx.

The Class() casting method has been shown to be faster than as casting, so it may be preferable to as when efficiency matters (and when not working with Dates and Arrays).

import flash.utils.*;

var d = Date( 1 );

trace( "'" + d, "'is type of: ",getQualifiedClassName( d ) );

var a:Array = Array( d );

trace( "'" + a, "' is type of: ", getQualifiedClassName( a ) );

    //OUTPUT
        //'Mon Jun 15 12:12:14 GMT-0400 2009 'is type of:  String
        //'Mon Jun 15 12:12:14 GMT-0400 2009 ' is type of:  Array

    //COMPILER ERRORS/WARNINGS:
        //Warning: 3575: Date(x) behaves the same as new Date().toString(). 
        //To cast a value to type Date use "x as Date" instead of Date(x).
        //Warning: 1112: Array(x) behaves the same as new Array(x).
        //To cast a value to type Array use the expression x as Array instead of Array(x).

`

+7  A: 

There are a couple of points in this discussion worth noting.

There is a major difference in how the two work, Class() will attempt to cast the object to the specified Class, but on failure to do so will (sometimes, depends on datatype) throw a runtime error. On the other hand using object as Class will preform a type check first, and if the specified object cannot be cast to the indicated Class a null value is returned instead.

This is a very important difference, and is a useful tool in development. It allows us to do the following:

var o:MyClass = myArray[i] as MyClass;

if(o)
{
    //do stuff
}

I think the usefulness of that is pretty obvious.

"as" is also more consistent with the rest of the language (ie: "myObject is MyClass").

The MyClass() method has additional benefits when working with simple data types (int, Number, uint, string) Some examples of this are:

var s:String = "89567";
var s2:String = "89 cat";
var n:Number = 1.9897;

var i:int = int(s); // i is = 89567, cast works
var i2:int = int(s2); //Can't convert so i2 is set to 0
var i3:int = int(n); // i = 1
var n2:Number = Number(s2); // fails, n2 = NaN

//when used in equations you'll get very different results
var result:int = int(n) * 10; //result is 10
var result:int = n * 10; //result is 19.89700
var result:int = int(s2) * 10; //result is 0

trace(s2 as Number); //outputs null
trace(s2 as int); //outputs null
trace(Number(s2)); //outputs NaN

This is a good and important topic, as a general rule I use "as" when working with Objects and Cast() when using simpler data types, but that's just how I like to structure my code.

Tyler Egeto
`as` may be more consistent with the language, but isn't it still more dangerous?Thanks for the response though – the intricacies of int/string/number casting are good to know.
David Wolever
What do you feel is more dangerous about it? What's dangerous is not handling all situation's properly, but that's a developer issue not a language one. I actually feel it's safer (type checking), and incredibly useful, and can result in cleaner code. var o:Class = a[i] as Class || new Class(); //great for this kind of thing
Tyler Egeto
To clarify why I think it's safer: it allows you to attempt a type cast without breaking things if it fails.
Tyler Egeto
This is how I generally cast for the reasons you specify. I want to gracefully handle the null. Runtime errors can have odd unintended effects and using 'as' allows me to avoid that without using try/catch blocks to handle the situation.
Joel Hooks
A: 

I use it when I have an ArrayCollection of objects and need to enumerate through them, or use a selector function.

e.g.

var abc:mytype = mycollection.getItemAt(i) as mytype

le dorfier
But why do you use `as` over `var abc:MyType = MyType(mycollection.getItemAt(i))`?Using `as` introduces the possibility of a subtle bug if `mycollection` contains something that isn't a `MyType` (see the fail-fast rule)
David Wolever
I use it because to me MyType(...) is mentally a cast and "as MyType" is mentally an alias, and I'm not casting it but rather asserting that's what it is to make the compiler happy (even if they might be the same in this case). But I'm on the duck-typing end of the bell-shaped curve, so it's probably mostly a reflection on how I think about code - I'd rather have it clear and simple that buttoned up at all the corners. I'm happy they left javascript well-enough alone rather than make actionscript out of it. I also use the "if(! object) {}" construct mentioned in another answer quite a bit.
le dorfier
+1  A: 

They actually do different things...when you say

myvar as ClassName

You are really just letting the compiler know that this object is either a ClassName or a subclass of ClassName

when you say:

ClassName(myvar)

It actually tries to convert it to that type of object.

so if your object is a or a descent of the class and you do not need to convert it you would use as

examples:

var myvar:String = '<data/>';
var othervar:XML = XML(myvar); //right

var myvar:String = '<data/>';
var othervar:XML = (myvar as XML); //wrong

var myvar:XML = <data/>;
var othervar:XML = myvar as XML; // right
John Isaacks
Alright, I see. So is it possible, then, to define my own type coercion rules? For example, if I was to write a Color class, how could I tell the compiler that `Color(0x443322)` is "a color with 0x44 red, 0x33 green and 0x22 blue"?
David Wolever
@David not sure how your Color class is set up but they are usually set as uint. Usually something that is expecting a color is really expecting a uint. the 0x in front means that 0x443322 is a hexadecimal number, which translates to 4469438 uint. So you shouldn't need to change it, but if you do, I think the best way would be to create a static method like Color.toColor(0x443322);
John Isaacks