AS3 for…in Object does not behave like AS2

April 7th, 2008 by Steven Sacks

So there's a difference in behavior in AS3 that people have pointed out to me. It has to do with using for…in an Object not returning the values in the order they were added to the Object. In AS2, this works that way, but in AS3, it doesn't.

Take the following code and run it in AS3 and AS2.

var obj:Object = {};
obj.a = 1;
obj.b = 2;
obj.c = 3;
for (var s:String in obj)
{
    trace(s + " = " + obj[s]);
}

You get the following output:

a = 1
b = 2
c = 3

In AS2, you get the opposite:

c = 3
b = 2
a = 1

The AS2 output seems more correct because for…in iterates backwards through whatever you're iterating through.

However, add any more keys to the object and AS3 starts to behave oddly.

var obj:Object = {};
obj.a = 1;
obj.b = 2;
obj.c = 3;
obj.d = 4;
for (var s:String in obj)
{
        trace(s + " = " + obj[s]);
}

In AS2, it outputs what you'd expect:

d = 4
c = 3
b = 2
a = 1

In AS3, however, you get this:

b = 2
d = 4
a = 1
c = 3

In fact, you can add and remove as many keys as you want in AS2 and it will give you consistent results every time you for…in. The most recent key added gets traced first down to the least recent key added.

By contrast, here's what the output in AS3 looks like for 8 keys

b = 2
f = 6
c = 3
g = 7
d = 4
h = 8
a = 1
e = 5

My friend Brad at Cartoon Network asked Grant Skinner about this recently and Grant told him that behavior is expected because those things are not indexed in order. While this makes sense logically, AS2 does not have this issue so it still seems like wonky behavior.

.NET maintains the proper order when you create a Dictionary to do the same thing (first in, first out), so I tried using a Dictionary in AS3, however, I get the same output as Object.

Java, on the other hand, seems to have a similar issue. Five keys results in

d = 4
a = 1
c = 3
b = 2
e = 5

And six keys

d = 4
a = 1
c = 3
f = 6
b = 2
e = 5

So for those making the transition from AS2 to AS3, be aware of this behavior change, especially if you've gotten used to the way AS2 handled it.

Posted in Actionscript, Bugs

6 Responses

  1. michal

    My guess would be that the implementation uses a hash table for both object properties and the Dictionary. This would guarantee fast O(1) inserts/searches but do not provide any reasonable ordering which is exactly what you're seeing.
    The alternative is a tree set which would provide alphabetical ordering of keys at the cost of slower O(log(n)) inserts/searches.
    I'm not sure what tests you did in Java as it gives you explicit choice of HashMap and TreeMap depending on your needs.
    The rule of thumb I was taught: unless you need the ordering use the hash set asd it's faster. So they did in AS3 I guess.
    I'm trying to think how you'd get first in/first out ordering on a dictionary and I can only come up with a list of key/value pairs which is extremely inefficient for anything other than inserts.

  2. Mike Keesey

    If your code relies on order, you should not be using for … in, anyway. The language's "contract", so to speak, does not guarantee any particular order.

    Java's collections make the distinction a little more explicit: most Collection objects don't guarantee any order, but the List subinterface does.

  3. corban baxter

    its things like this that make me want to never be a "REAL" programmer!

  4. Philip Thonbo

    what about the fact that you in as2 could use displayObjects(movieclips) and whatever to run a for(i in this)
    on. and it would return EVERYTHING incl [type Function] script objects visible objects everything - you could trace a mc.filters[0] to get vars from a filter object created in flash ide - [object BlurFilter] now you can ONLY iterate through an strict Object object - it is so lame tell me if you find any work around on THAT

  5. calvin

    I agree that the main problem in as3 is the fact that you can only iterate over genuine Object objects…
    Even casting to Object doesnt work..so there is a LOSS of functionality here. I wish I knew a workround this was quite an elegant way of doing something which now I see no solution but to engineer a specific array or other.

  6. Steve Kamerman

    To get a similar effect in AS3 you need to use an Array of objects, like this:

    var data:Array = [
    {a: 1},
    {b: 2},
    {c: 3}
    ];

    for (var i:uint=0;i<data.length;i++){
    var obj:Object = data[i];
    var s:String;
    for(s in obj){break;} //set s

    trace(s + " = " + obj[s]);
    }

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

About Steven Sacks

I am a professional Flash developer with over 13 years of programming experience. I have consulted for high-profile agencies and companies in San Francisco, Los Angeles, Atlanta and New York, and developed numerous award-winning websites and rich internet applications for clients including Adobe, Fox Sports, FX Networks, Anheuser-Busch, GE, DirecTV, ESPN, The Weather Channel, Home Depot, and Coca-Cola.

I am the author of the open-source Gaia Framework for Adobe Flash, which dramatically reduces development time and makes developing Flash sites much easier.