Problems understanding correct Tables item removal

Coming from C/C++ I really feel to old for this Lua s… and i really bothers me. Anyway…

I’m trying to get the basics down regarding tables and how to add/remove stuff properly.

My simple example is creating three blocks falling down to the ground and as they hit, they are supposed to be removed from the table (and also be removed correctly from the physics engine).

To avoid crashes in the physics engine I do not remove the item directly when a collision is detected, but mark it to be removed. Then I call the removeBlocksMarkedForRemoval() as per frame drawing.

The entire code looks like this:

local w = display.contentWidth local h = display.contentHeight local physics = require("physics") physics.start() -- Ground local ground = display.newRect(w/2, h-5, w, 10) ground.myName = "earth" physics.addBody(ground, "static", { density=5.0, friction=0.3, bounce=0.0}) local blockArr = {} local function addBlock()     local newIdx = #blockArr+1     blockArr[newIdx] = display.newRect(math.random(w/2-100, w/2+100), -30, 30, 30)     blockArr[newIdx].markedForRemoval = false     blockArr[newIdx].myName = "block"     physics.addBody(blockArr[newIdx], "dynamic", { density=2.0, friction=0.9, bounce=0.5}) end local function removeBlocksMarkedForRemoval()     for i = #blockArr, 1, -1 do         if (blockArr[i].markedForRemoval == true) then             physics.removeBody(blockArr[i])             blockArr[i]:removeSelf()             blockArr[i] = nil         end     end end timer.performWithDelay(250, addBlock, 3) -- Hit  local hit = function(e)     if (e.phase == "ended" and e.object1.myName == "earth" and e.object2.myName == "block") then         e.object2.markedForRemoval = true     end end local frameRedrawListener = function(e)     print("blocks before call to removeBlocksMarkedForRemoval() = " .. #blockArr)     removeBlocksMarkedForRemoval()     print("blocks after call to removeBlocksMarkedForRemoval() = " .. #blockArr) end -- Add event listeners Runtime:addEventListener( "enterFrame", frameRedrawListener ) Runtime:addEventListener( "collision", hit ) 

But when I run it I get a " attempt to index field ‘?’ (a nil value)" for the line

if (blockArr[i].markedForRemoval == true) then 

And I don’t understand why. It’s obvious that I’m doing something stupid.

But what is the correct way of doing such a thing?

This error happens when you try to access property of not existing object. In our case blockArr for some index i doesn’t exist. You ask why: because you created hole in table. Hash returns you size of table so you loop through it. But you set one element to nil and there is no object here which property you can access. This is the reason of error.

Solution:
There is build in function table.remove() which removes element from table and shifts other elements down. You should use it on i-th element after you nil it. Also remember to loop down (as you have done) because shifting will affect higher indexes.

This is true only when you use table as array (with w indexes). When using it as dictionary (lua tables are dual and even can mix both) it a bit different :slight_smile:

Yesss! Thanks a bunch, piotrz55  :slight_smile:

I thought NIL’ing the table element automatically removed it from the table, but it obviously does not.

Thanks again!

This error happens when you try to access property of not existing object. In our case blockArr for some index i doesn’t exist. You ask why: because you created hole in table. Hash returns you size of table so you loop through it. But you set one element to nil and there is no object here which property you can access. This is the reason of error.

Solution:
There is build in function table.remove() which removes element from table and shifts other elements down. You should use it on i-th element after you nil it. Also remember to loop down (as you have done) because shifting will affect higher indexes.

This is true only when you use table as array (with w indexes). When using it as dictionary (lua tables are dual and even can mix both) it a bit different :slight_smile:

Yesss! Thanks a bunch, piotrz55  :slight_smile:

I thought NIL’ing the table element automatically removed it from the table, but it obviously does not.

Thanks again!