Anomaly NG vs Vanilla
BlitzMax Forums/BlitzMax NG/Anomaly NG vs Vanilla
| ||
Hi, I've encountered something weird: Type TDisposable Field link:TLink End Type Local lst:TList = New TList For Local i:Int = 1 To 500 Local dp:TDisposable = New TDisposable dp.link = lst.AddLast(dp) Next Graphics(1024, 768) For Local d:TDisposable = EachIn lst Cls If KeyHit(KEY_ESCAPE) Exit RemoveLink(d.link) DrawText(lst.count(),10,10) Delay(100) Flip Next In vanilla I see the counter going down as expected, objects get removed from the list at a steady pace. In NG the counter gets stuck after the first iteration. |
| ||
It is because you do a "concurrent modification" of the list. You iterate through a list... and then while you are inbetween, you delete something. The Iterator is something "added on top" of the list ... so it is not aware of the changes you did. Should happen with vanilla too - Brucey added something in the last weeks which should allow concurrent modification (at least I think that the corresponding commit was done for that subject) @ exit You exit if "something" is > 2 ... which might happen already on the first iteration. Dunno what you mean with "stuck" exactly. Edit: you seem to have your OP edited meanwhile so the "something"-part is gone. Edit2: If you want to remove something from a list you could have an empty array of TLinks right before the for-loop. If you now want to remove one of the list entries in that loop, you do not delete it directly (concurrent modification) but append it to the previously empty array (arr :+ [link]). After the for loop you loop over all entries in the array and remove it from the list. This avoids concurrent modification of the TList. bye Ron |
| ||
Sorry, I edited my example because it had too much unnecessary code. It does not happen in vanilla, nor should it IMO. TList.count() should always reflect the amount of items in the list, no matter when items were deleted. But consider this example then: Type TDisposable Field link:TLink End Type Local lst1:TList = MakeAList() Local lst2:TList = MakeAList() Graphics(1024, 768) While Not KeyHit(KEY_ESCAPE) Cls RemoveFirstItem(lst1) RemoveSomeItem(lst2) DrawText(lst1.count(), 10, 10) DrawText(lst2.count(), 10, 30) Delay(100) Flip Wend Function RemoveFirstItem(lst:TList) lst.RemoveFirst() End Function Function RemoveSomeItem(lst:TList) For Local d:TDisposable = EachIn lst RemoveLink(d.link) Exit Next End Function Function MakeAList:TList() Local lst:TList = New TList For Local i:Int = 1 To 500 Local dp:TDisposable = New TDisposable dp.link = lst.AddLast(dp) Next Return lst End Function Problems might be related to RemoveLink |
| ||
You are right. "RemoveSomeItem" (in its current implementation) could be replaced with: RemoveLink(lst.FirstLink()) And it does indeed _seem_ to not do anything... but that is not the case. The real bug is, that Brucey adjusted TList for NG - and it caches "count". I adjusted your code to make it visible: As you can see (hopefully) it prints multiple IDs ... so each time it removes an _other_ disposable entry. @ count I am not sure but in my proposal to caching count (for map or so?) I used an "invalidate count on change" approach. Brucey uses an "add/subtract on change" approach. So if he misses an "+- 1" in certain situations - then "count" becomes "wrong". Edit: Seems the "link.remove()" command bypasses the _count-cache totally as it never uses something from the TList-object but manipulates the children directly (neighbouring TLink siblings). Filed an issue (with a shoter example). https://github.com/bmx-ng/brl.mod/issues/44 bye Ron |