AS3 for…in Object does not behave like AS2
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
April 7th, 2008 at 2:57 pm
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.
April 7th, 2008 at 3:33 pm
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.
April 11th, 2008 at 8:27 am
its things like this that make me want to never be a "REAL" programmer!
May 30th, 2008 at 7:37 am
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
June 24th, 2008 at 11:50 am
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.
July 2nd, 2008 at 12:40 pm
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]);
}