I published similar results on my blog a few years back. The reason it is slower is that there are more byte codes involved and those byte codes take more time. The more you know, and the more information you have handy, the less work there is to do and we can make more assumptions.
For "b.id", the byte code is more or less: Push "id" Push "b" GetProperty For "(b as button).id", the byte code is roughly: Push "id" Push b Push button Coerce GetProperty For "o.id", the byte code is roughly: Push "id" Push "o" FindProperty and FindProperty is much slower. Note that it takes 10000000 accesses to feel a 1 second difference. There's more byte code involved in using "as" so if you did it everywhere your SWF will be larger and take up more memory at runtime and could offset those gains. However, if you've got the time, it might be worth doing from a code maintenance standpoint as the compiler will help you find misspellings and what not. Alex Harui Flex SDK Developer Adobe Systems Inc.<http://www.adobe.com/> Blog: http://blogs.adobe.com/aharui From: [email protected] [mailto:[email protected]] On Behalf Of Pan Troglodytes Sent: Monday, May 04, 2009 7:19 PM To: flexcoders Subject: [flexcoders] for better performance, use "as" rather than just leaving an object as Object? I was curious as to the difference between a few different ways of approaching the situation of an itemRenderer having a "data" property and deciding whether or not to use "as" to make all the type checking happy. So I tried some test code and found that it made a big difference whether you use "as" or just leave the data property as an Object. If you leave it as an Object, you get a performance hit on the order of 40%+ longer than if you use "as" to cast it first. Here are the ways I tested it. I just decided to pull the "id" property because it's something that is just a simple access of a private variable, no complicated stuff. var b:Button = new Button; var o:Object = b; var s:String; s = b.id<http://b.id>; s = (o as Button).id; s = Button(o).id; s = UIComponent(o).id; s = (o as UIComponent).id; s = o.id<http://o.id>; I did get a bit fancy and put them in a loop and a timer to isolate each one. The full code is included below. What I found was along the lines of this (give or take a few %): Button: 3.16 Button(): 4.06 129% as Button: 4.14 131% UIComponent(): 3.98 126% as UIComponent: 4.03 128% Object: 5.38 170% I put in the UIComponent ones because sometimes I cast it to a superclass because I might get several different subclasses passed into a function. So what I've found is that if you ignore than noise, the middle four methods are also approximately the same in timings. But the Object one is far worse. This probably won't come as any surprise to the Adobe folks or the people who have been working with Flex a bit more in-depth. I found it rather useful information, though, considering I'm trying to shave off some time in various places in one of my apps. Granted, it won't matter as much outside of loops. So many things return the items as objects, such as Arrays/ArrayCollection, the "data" property of item renderers, etc. I think I'm just going to make it a habit to put "as" in my code (and not the format of Class(variable) because sometimes that triggers a function rather than just doing a casting) all the time. It helps catch errors by doing strict type checking (as long as you aren't using dynamic classes) and it's a little faster to boot. Still, I wish it was as fast as the top line where you don't have to do any casting/as at all. Any thoughts on that or anything else I've missed? Any flash insiders want to give your insight on why it works this way under the hood? <?xml version="1.0" encoding="utf-8"?> <Application xmlns="http://www.adobe.com/2006/mxml" > <Script> <![CDATA[ import mx.core.UIComponent; private var timer:Timer = new Timer(100); private var mode:int = 0; private function doClick(e:Event):void { if (timer.running) { timer.stop(); timer.removeEventListener(TimerEvent.TIMER, timerClick); } else { timer.addEventListener(TimerEvent.TIMER, timerClick); timer.start(); } } private var last:Number; private var b:Button = new Button; private var o:Object = b; private var s:String; private var i:int; private var traceStart:Date; private var loops:int = 10000000; private var time:Number; private function timerClick(e:Event):void { timer.stop(); switch(mode) { case 0: trace(); traceStart = new Date(); for (i = 0; i < loops; i++) s = b.id<http://b.id>; time = (new Date().time - traceStart.time); trace("Button:\t\t", (time / 1000).toFixed(2)); last = time; break; case 1: traceStart = new Date(); for (i = 0; i < loops; i++) s = (o as Button).id; time = (new Date().time - traceStart.time); trace("as Button:\t", (time / 1000).toFixed(2), "\t", ((time / last) * 100).toFixed(0) + "%"); break; case 2: traceStart = new Date(); for (i = 0; i < loops; i++) s = Button(o).id; time = (new Date().time - traceStart.time); trace("Button():\t", (time / 1000).toFixed(2), "\t", ((time / last) * 100).toFixed(0) + "%"); break; case 3: traceStart = new Date(); for (i = 0; i < loops; i++) s = (o as UIComponent).id; time = (new Date().time - traceStart.time); trace("as UIComponent:\t", (time / 1000).toFixed(2), "\t", ((time / last) * 100).toFixed(0) + "%"); break; case 4: traceStart = new Date(); for (i = 0; i < loops; i++) s = UIComponent(o).id; time = (new Date().time - traceStart.time); trace("UIComponent():\t", (time / 1000).toFixed(2), "\t", ((time / last) * 100).toFixed(0) + "%"); break; case 5: traceStart = new Date(); for (i = 0; i < loops; i++) s = o.id<http://o.id>; time = (new Date().time - traceStart.time); trace("Object:\t\t", (time / 1000).toFixed(2), "\t", ((time / last) * 100).toFixed(0) + "%"); break; } mode = (mode + 1) % 6; timer.start(); } ]]> </Script> <Button click="doClick(event)"/> </Application> -- Jason

