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

Reply via email to