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