UPDATE 2011.09.13 This bug has been resolved by Adobe. The example code below now exhibits the correct behavior. Original question is below.
It took me many hours to narrow down a problem in some code to this reproducible error, which seems to me like a bug in AVM2. Can anyone shed light on why this is occurring or how to fix it?
When the value at index 1 is deleted and a value is subsequently set at index 0, the non-existent (undefined) value at index 1 will now show up in a foreach loop. I have only been able to produce this outcome with index 1 and 0 (not any other n and n-1).
Run this code:
package
{
import flash.display.Sprite;
public class Main extends Sprite
{
public function Main():void
{
var bar : Array = new Array(6);
out(bar);
//proper behavior
trace("bar[1] = 1", bar[1] = 1);
out(bar);
//proper behavior
trace("delete bar[1]", delete bar[1]);
out(bar);
//proper behavior
trace("bar[4] = 4", bar[4] = 4);
out(bar);
//for each loop will now iterate over the undefined position at index 1
trace("bar[0] = 0", bar[0] = 0);
out(bar);
trace("bar[3] = 3", bar[3] = 3);
out(bar);
}
private function out(bar:Array):void
{
trace(bar);
for each(var i : * in 开发者_JS百科bar)
{
trace(i);
}
}
}
}
It will give this output:
,,,,,
bar[1] = 1 1
,1,,,,
1
delete bar[1] true
,,,,,
bar[4] = 4 4
,,,,4,
4
bar[0] = 0 0
0,,,,4,
0
undefined
4
bar[3] = 3 3
0,,,3,4,
0
undefined
4
3
EDIT: See answer for likely cause of the bug. Unable to find a fix. My solution was to code a special case where if index 0 is being set and index 1 does not exist, delete index 1 after setting index 0. Not exactly an elegant solution :\
It looks like you're running in to a bug that seems to happen when AS3 arrays are split into a dense array part and a "rest" hashtable part.
It's been reported as an "Actionscript Core Language" bug to Adobe here: FP-3477
There's also a couple of blog-post links there to other developers that have run into the (probably) same issue.
Although your example code doesn't re-insert the same object, there might be related issues to how the VM is optimizing low-range literal numbers (often as shared, constant 'objects')
While clearly a bug, I'd say it has more to do with the fact that the array values are in some form of weird state when initialized as var bar : Array = new Array(6);
, they should be iterated over to begin with as far as I can see.
I actually never use delete bar[1]
to get rid of a value in an array, I always go for bar.splice(1, 1)
*, when doing this all unset indices will begin to trace as undefined
, so there's clearly something strange going on.
While I suspect you're not really looking for a workaround, I'd just try to live with the potentially iterated empty positions, either handling them as you encounter them or by doing a for (var i:int = 0; i < bar.length; i++)
style loop instead.
If you don't need the array-type behaviours, using Object
could work as well, it doesn't seem to have this issue.
* this is just by preference, no real reason.
精彩评论