Sunday, June 20, 2010

As3 ArrayCollection Sort "Feature"

Consider my confusion when I setup the debugger:

this._listData.owner.dataProvider.getItemIndex(this._data) = -1 [0xffffffff]
this._listData.owner.dataProvider.getItemAt(11)===this._data = true

As a background you should know that this._listData.owner.dataProvider is an ArrayCollection. Based on what I know about "equality" in as3 the above is an impossible situation.

this._listData.owner.dataProvider.getItemAt(11)===this._data

That means that the 2 reference points to the same object. So if the 11th element is same that this.data why is it not found in the collection?????

Well the explanation is filed as a bug @Adobe. The problem is that the bug is more like an undocumented feature:
If you set a sort on the collection and the sort's comparator has a bug or simply does not pass the equality check for the same object(sounds like a bug) than you get to see the above.

In my case the trials are not over. The comparator's equality does work...

After hours of testing and heated debates..I spare you details... here is the explanation:

Our sort comparator used a mutable variable that described sort order ASC or DESC. Because the variable was mutable, it was changed by other things in the application. Leading to a an unpleasant and hard to debug problem:
  1. We create a sort function and assign it to an ArrayCollection.
  2. We add records to the ArrayCollection and call sort.
  3. Change the sort order variable.
  4. Call getItemIndex(this._data) and get -1
The problem is that the internals of the Collection assume that collection is sorted(it is not sorted by the sort as of #3). It tries to walk a tree(I assume after debug) using the comparator, but because the tree was created with a different sort function the tree walking (search) will fail.

Lesson #1: It is very important that any data that is in the sort function that is not passed as itemA/itemB can not change. If it needs to change recreate the sort/comparator. 

Lesson #2: Use a sort/comparator if you want to modify the default behavior of getItemIndex(). If you want to allow for customizing equality, use a Sort object on an ArrayCollection.