16

Is there any difference of use, efficiency or background technique between

var mc:MovieClip = MovieClip(getChildByName("mc"));

and

var mc:MovieClip = getChildByName("mc") as MovieClip;

?

The choice is just matter of convention, preference or are there cases where you can't use one?

8 Answers8

22

This article describes the differences well:

A key difference between casting and the as operator is the behavior on failure. When a cast fails in ActionScript 2, null is returned. When a cast fails in ActionScript 3, a TypeError is thrown. With the as operator in ActionScript 3, whenever a cast fails the default value for the datatype is returned.

as also allows you to cast to Array, which wasn't possible before since the conversion function Array() took precedence.

EDIT: concerning performance, using as is reported to be faster than the function call style casting in various articles: [1] [2] [3]. The first article cited looks at the performance differences in depth and reports that as is 4x-4.5x faster.

EDIT 2: Not only is as 4x-4.5x faster in the normal best case, but when you wrap the (cast) style conversion in a try-catch block, and an error actually ends up being thrown, it's more like 30x - 230x faster. In AS3, if you think you're going to do something exceptional (in that it could throw an error) then it's clear that you should always look before you leap. Never use try/catch unless forced to by the API, and indeed that means to never (cast) It also is instructive to look at the performance implications of try/catch even when no exception is thrown. There's a performance penalty to setting up a try/catch block even in the happy case that nothing goes wrong.

scriptocalypse
  • 4,942
  • 2
  • 29
  • 41
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
  • Note that if performance is critical, that using `as` is slower than a regular cast. So if you know that the cast will not fail, you might just want to cast the variable instead of using `as`. – Sunil D. Jan 11 '13 at 06:40
  • 1
    Hmm, I seem to be wrong according to some tests that are linked to in another answer. Perhaps its an "old wives tale", but I was told using `as` was slower and just believed it. Any thoughts? – Sunil D. Jan 11 '13 at 06:56
  • 1
    SunilD. It's a wives tale. In addition to the linked article on Jackson Dunstan's blog and his test suite, my own independent tests verify his. 'as' truly is the winner on all counts. – scriptocalypse Jan 11 '13 at 15:10
  • So for absolute clarity then: absolutely never cast in the usual sense, always use as, right? – Panzercrisis Jul 19 '13 at 01:58
  • 1
    @Panzercrisis That would appear to be the consensus. I've never actually coded in ActionScript - this answer is just a product of googling and scriptocalypse's edit. – Paul Bellora Jul 19 '13 at 19:32
  • The performance difference is insignificant in any non performance-critical code. As a result my philosophy is to code to demonstrate intention and catch errors as early as possible in your application. My rule: Use the constructor cast in any situation where you expect the cast to be successful. MovieClip(mc); Only use 'as' cast when you expect the cast to fail in some normal use-cases. This way a failed cast will immediately throw, alerting you to a problem. – Craig Jun 10 '14 at 20:44
  • What happens when you send something to a function that expects a more primitive type? Like if you send a Sprite to a function that takes a DisplayObject? If you sent it something that didn't extend DisplayObject, you'd get a type error -- so presumably it's equivalent to a (cast) call and just as slow. Right? Does that mean it's better to use an "as" operator before sending something to that function? What if the function expects its argument to conform to an interface like IEventDispatcher...? – joshstrike Sep 28 '14 at 01:22
  • Also, too... what about "for each (var a:DisplayObject in vectorOfSprites)" -- is that going to perform a cast on every single one? – joshstrike Sep 28 '14 at 01:26
4

Since nobody answered the performance aspect directly yet, and it was in your question, as is dramatically more efficient and faster at runtime than (cast) in AS3.

http://jacksondunstan.com/articles/830

Combined with all the other factors I see absolutely no reason to ever use (cast) and feel it should be avoided completely.

Retracted comment below actually reminds me of a good point as well in regards to this. If you (cast) then you're almost assuredly going to find yourself in a situation where you'll have to try/catch

try{
    SubType(foo).bar();
}catch(e:TypeError){
    // Can't cast to SubType
}

Which is murderously slow. The only way around that is an is check first

if(foo is SubType){ 
  SubType(foo).bar();
}

Which just seems wrong and wasteful.

scriptocalypse
  • 4,942
  • 2
  • 29
  • 41
  • 1
    Hmm, original comment retracted (On a tablet and I can't delete it, so replacing it with this useless comment). – Sunil D. Jan 11 '13 at 06:45
  • It's okay, your comment (before you retracted it) reminded me of something else that's valuable to point out. – scriptocalypse Jan 11 '13 at 07:28
  • 2
    Actually using the is-check is a definite best practice. You should always make sure the cast will be successful. Otherwise you'll be testing for `null` anyway, which is a definite no-no. – Creynders Jan 11 '13 at 09:20
  • @Creynders Why is a null check a no-no? It's no slower at runtime than a cast. If you're going for performance above all else, calling 'is' before calling 'as' feels just as strange as calling 'is' before casting. – scriptocalypse Jan 11 '13 at 15:06
  • @scriptocalypse Let me rephrase it: "`null` should be avoided altogether, when possible." (Which is the case here) There's tons to be found on why `null` is devilish, but in short: `null` does not provide any context on how to handle it. Is it the result of a bad assignment, cast, uninitialized member, etc.? The AVM also chokes on it if you try to access a member, throwing fringe case generic errors, which are very hard to hunt down. Also, you loose any type information, you have no idea what type the null object should've been. And ... why does it feel strange? (calling `is` before a cast) – Creynders Jan 14 '13 at 10:07
  • 2
    @Creynders the main reason it feels strange to do `is`/`as` is because a failed `as` is implicitly `foo is Bar == false`. Why test it twice when you can do `var foo:Bar = x as Bar;` followed by `if(foo){}`. I would NEVER recommend calling a member like this `(foo as Bar).member()`. – scriptocalypse Jan 14 '13 at 22:32
  • ok, I hear you. In my mind it's a validity check followed by an operation, just as you would check an Array index before using it to access the Array. – Creynders Jan 16 '13 at 09:19
  • I also use `as` most of the times for a few reasons. If a cast fails with `(cast)` it will throw an error, and most of the times you don't want errors as long as you can use simple `if` statements. Second, most of the times I use it with interfaces, and I rarely know what exactly the class is. So checking with `var foo = x as Y; if (foo)` feels pretty natural to me, it's fast and it's not needing try-catch, which is slooow. – Andrey Popov Aug 30 '15 at 19:05
2

AS3 Casting one type to another contains the answer that answers this as well: the "as" keyword assigns null when the conversion fails, otherwise it throws a TypeError.

Community
  • 1
  • 1
MarioDS
  • 12,895
  • 15
  • 65
  • 121
1

It is best practice to use the as keyword.

as has the advantage of not throwing an RTE (run-time error). For example, say you have a class Dog that cannot be cast into a MovieClip; this code will throw an RTE:

var dog:Dog = new Dog();
var mc:MovieClip = MovieClip(Dog);

TypeError: Error #1034: Type Coercion failed: cannot convert Dog to MovieClip.

In order for you to make this code "safe" you would have to encompass the cast in a try/catch block.

On the other hand, as would be safer because it simply returns null if the conversion fails and then you can check for the errors yourself without using a try/catch block:

var dog:Dog = new Dog();
var mc:MovieClip = Dog as MovieClip;
if (mc) 
    //conversion succeeded
else
    //conversion failed
Foggzie
  • 9,691
  • 1
  • 31
  • 48
1

Prefer the use of a cast to the use of the as operator. Use the as operator only if the coercion might fail and you want the expression to evaluate to null instead of throwing an exception.

Do this:

IUIComponent(child).document

Not this:

(child as IUIComponent).document

Coding Conventions

Raja Jaganathan
  • 33,099
  • 4
  • 30
  • 33
  • +1 For counterpoint with citation (though the article doesn't explain why). – Paul Bellora Jan 11 '13 at 11:59
  • 1
    @PaulBellora The reasoning in the article is simply because it's the Flex coding convention style guide. In other words, it's completely arbitrary and it's based on the coding style that the Flex framework authors used. – scriptocalypse Jan 11 '13 at 15:03
  • I would strongly argue about that. As long as you are doing coercion, it might fail for numerous reasons. And there are no benefits of using the first way.. – Andrey Popov Aug 30 '15 at 19:08
1

(cast) and "as" are two completely different things. While 'as' simply tells the compiler to interpret an object as if it were of the given type (which only works on same or subclasses or numeric/string conversions) , the (cast) tries to use a static conversion function of the target class. Which may fail (throwing an error) or return a new instance of the target class (no longer the same object). This explains not only the speed differences but also the behavior on the Error event, as described by Alejandro P.S.

The implications are clear: 'as' is to be used if the class of an object is known to the coder but not to the compiler (because obfuscated by an interface that only names a superclass or '*'). An 'is' check before or a null check after (faster) is recommended if the assumed type (or a type compatible to auto-coercion) cannot be 100% assured.

(cast) is to be used if there has to be an actual conversion of an object into another class (if possible at all).

PeterP
  • 11
  • 1
0

Further to launch or not RTE, or return null, there is a significant difference when we manage errors in a swf loaded into a separate application domain.

Using Loader.uncaughtErrorEvents to handle errors of the loaded swf; if we cast like 'event.error as Error', the resulting error will have the original stack trace (the same that had been caught in the swf that caused the error) while if cast that with Error (event.error), the stack trace of the error will be changed by the current stack trace (in which the cast was made).

Sample Code:

if (event && event.error && event.error is Error) {
    debug ("Casting with 'as Error'") 
    debugStackTrace (event.error as Error); 
    debug ("casting with 'Error (...)'"); 
    debugStackTrace (Error (event.error)); 
}

Sample output:

Casting with 'as Error' 
ReferenceError: Error # 1056 
at Player / onEnterFrame () 
casting with 'Error (...)' 
Error: ReferenceError: Error # 1056 
at package :: HandlerClass / uncaughtErrorHandler () 
at EventInfo / listenerProxy ()
0

var mc:MovieClip = MovieClip(getChildByName("mc"));

will DIRECTLY SET IT AS movieclip

var mc:MovieClip = getChildByName("mc") as MovieClip;

will make mc act like a movieclip, if required type are same

wuiyang
  • 409
  • 2
  • 5
  • 18