Removing list items: Part 2
After tossing the ideas from my previous post around with Murphy, we refined the concept a bit. Items:
- The focus is now on discarding dead items with “removeCurrent varname” rather than keeping live ones.
- Instead of a separate “removeEach” loop, the removal feature will use the regular forEach. If the body of the forEach contains a removeCurrent command, the extra framework will be added.
- The list structure basically becomes corrupted during the iteration and is fixed at the end. A return command or an exception being thrown would normally prevent the list from performing that final clean-up. Code needs to be adjusted to accommodate that.
- Regular forEach loops can be called on iterable objects or iterator objects. The forEach-remove variant could only be called on iterable lists – meaning also that we can use indicies to control the loop progression instead of creating an iterator.
Here’s an example of how it would all work under the hood. This Slag code:
forEach (mob in monsters) mob.update if (mob.dead) removeCurrent mob endForEach
would be transformed into this:
local var list = monsters local var limit = list.count local Boolean kept = false local Int32 save_pos = 0 local Int32 read_pos = 0 try while (read_pos < limit) if (kept) save_pos++ else kept = true local var mob = list[read_pos] monsters[save_pos] = mob read_pos++ # user code mob.update if (mob.dead) kept = false endWhile if (kept) save_pos++ list.discard(save_pos,read_pos-1) catch (Exception err) if (kept) save_pos++ list.discard(save_pos,read_pos-1) throw err endTry
Great solution Abe (and Murphy). I’ve certainly run into this problem before… practically in every game I’ve ever worked on, as a matter of fact! It’s somewhat shocking that in all my time in school and at IBM, I’ve never seen such a simple solution. Good stuff!
-Jacob