Nil but still not nil?

I have a module:

local M = {} M.starTable = {} M.displayObjectGroup = {} function addStarText()     M.starTable.starText = display.newText({ ... })     M.displayObjectGroup[#M.displayObjectGroup + 1] = M.starTable.starText end return M

Later, I empty the displayObjectGroup:

 for i = 1, #M.displayObjectGroup do     M.displayObjectGroup[i]:removeSelf()      M.displayObjectGroup[i] = nil  end

I then test for nil:

if (M.starTable.starText ~= nil) then --- end

I would expect the value to be nil but it is not. The display object is not there but it still is not nil, kind of in a zombie state. Why?

How can I either set it to a “true nil” when emptying, or, how can I see if the display objects is there or not in an if-statement?

M.starTable.starText is a reference to the last created textobject. When you remove all the texts, you remove their graphi representation, but the data (functions, values etc.) associated with it are still there because of the M.starTable.starText reference.

So, if you want M.starTable.starText to be nil just set it to nil.

M.starTable.starText = nil

I don’t even know why you use M.starTable.starText instead of a local variable in the first place.

@torbenratzlaff

But why is

M.displayObjectGroup[i] = nil

not the same thing as

M.starTable.starText = nil

when “M.starTable.starText” is in the group? I would have assumed that both the statements above remove the exact same data.

The code was just an example, the real module is much more complex and M.starTable is used in a lot of places.

First, this is a variable

M.starTable.starText

Assigning nil to it will nil the ‘variable’ so it doesn’t reference anything.

Second, you’re misunderstanding the concept.  ‘nil’ has no effect on the object itself.  The purpose of ‘nilling’ references is to ensure no variable holds a reference to the object so Lua can remove the object.  

‘nilling’ == clearing (a variable)

Lua knows if there are references to an object and until they are all cleared, the object will stay in memory.

Third, VERY IMPORTANT, this code is completely wrong and dangerous:

M.displayObjectGroup[i] = nil

If ’ displayObjectGroup’ is an actual display group, you never want to assign to a child index. I honestly don’t know what that will do, but it won’t be good.

When you remove an object using display.remove() or obj:removeSelf(), it is AUTOMATICALLY removed from the group that owns it and that group AUTOMATICALLY clears its reference to that object.

The ONLY reason to ever use a child index to reference an entry in a group is to operate on the object at that index.  NEVER EVER assign to a child index of a display group.

Oh, and if ‘displayObjectGroup’ is just a table, then using the word ‘group’ in the name is just bad practice and super confusing.

@roaminggamer

displayObjectGroup is actually table, not a display group. I agree, a really poor naming choice. Sorry about the confusion…

Given that, I follow the docs for removing display objects (https://docs.coronalabs.com/api/type/DisplayObject/removeSelf.html)

using both :removeSelf() and nilling. However, the docs also say this:

What remains of the object is simply a plain Lua table with all non-display object properties — the metatable is set to nil and all properties relating to display object are removed. Thus, if there are still references to object in Lua, they will simply be references to a normal Lua table.

In other words, testing for nil as I do in my first posting:

if (M.starTable.starText ~= nil) then --- end

will not work. So, the question remains: how can I see if a display object exists or not?

I probably won’t be able to help without seeing all of the code, but I don’t really want to… so let me suggest what I always suggest.

Never use numerically indexed tables to store references to display objects unless you absolutely need to know the order they were created in.

I always do this instead:

local myObjects = {} ... then later local function onTouch( self, event ) if( event.phase == "ended" ) then myObjects[self] = nil -- Clear entry indexed by this object in table display.remove(self) -- remove object (done; it will now free) end return false end -- Randomly place 10 circles and attach common touch listener. for i = 1, 20 local tmp = display.newCircle( math.random( 100, 400 ), math.random( 100, 400 ), 10 ) myObjects[tmp] = tmp tmp.touch = onTouch tmp:addEventListener( "touch" ) end -- Now, touching the circles removes them and cleans their references. Easy-Peasy

Also, if you’re using multiple variables to reference the same object and those variables are global or file-level in scope… 

This is kind-of a bad practice as you’ve discovered.  

That said, if you keep objects in a ‘object’ indexed table you can do this:

myObjects[M.starTable.starText] = nil -- clear the table entry/reference display.remove(M.starTable.starText) -- remove the object M.starTable.starText = nil -- clear the variable

As far as, checking if an object exists?  If you mean, “How do I check whether I cleared all references to it?”

The simple answer is, you can’t (easily do this).  You’re better off simplifying your code to have as few references to the same object as possible.

However, if you meant, “I have a reference to an object.  How do I check to see if that reference is pointing to a valid display object or a table stub?”

There are several ways, but one of the most robust I know is:

local objRef = display.newCircle( 10, 10, 10 ) print( "Is Valid? ", (objRef.removeSelf ~= nil and type(objRef.removeSelf) == "function" ) ) display.remove( objRef ) print( "Is Valid? ", (objRef.removeSelf ~= nil and type(objRef.removeSelf) == "function" ) )

Prints: 

Is Valid? true Is Valid? false

@roaminggamer

Again, thank you very much for your answers.

The whole reason I’m using a table to store all display objects is to be able to delete them all when switching from one scene to another. I know composer does that for me but I do not use composer in this app (rookie mistake, long story). So, each display object created is put in displayObjectGroup and when switching to another scene I simply delete them all by

 for i = 1, #M.displayObjectGroup do     M.displayObjectGroup[i]:removeSelf()      M.displayObjectGroup[i] = nil  end

Given this, would you use an indexed table to keep track of all display objects like I do or is there a better solution (apart from using composer, which I do in my newer apps)?

You mention “multiple variables to reference the same object”. Am I doing that? If you look in my original post, isn’t M.starTable.starText the only reference to the text object? Or does putting it in an indexed table itself create another reference to it?

Regarding your last post, I assume object.removeSelf means the function object:removeSelf() and if I understand your code correctly that function becomes nil after the object is removed and the variable is nilled? Is that correct?

  1. Use an actual display group and remove the display group.  This will automatically delete its children.

    – At start of scene/game/level/… local group = display.newGroup() – Now add objects directly when you make them: local someVar = display.newCircle( group, 10, 10, 10 ) display.newRect( group, 10, 10, 10, 10 ) – … etc … – Later: display.remove( group ) – I NEVER use removeSelf() it is unsafe if you goof up and call it twice. group = nil someVar = nil – At this point, the objects are all removed. Now, as long as all reference variables are cleared – or as long as they fall out of scope and are automatically removed by Lua, the – objects will be garbage collected.

  2. multiple variables/references - Yes you are.  The table entries are a ‘reference’ too.

  3. re: your last question yes.  You’re checking if the ‘Corona stuff’ has been stripped off the reference/object.  If it is gone, then the reference is to a stub.

Ok, I learned a lot here… Many thanks, roaminggamer!

M.starTable.starText is a reference to the last created textobject. When you remove all the texts, you remove their graphi representation, but the data (functions, values etc.) associated with it are still there because of the M.starTable.starText reference.

So, if you want M.starTable.starText to be nil just set it to nil.

M.starTable.starText = nil

I don’t even know why you use M.starTable.starText instead of a local variable in the first place.

@torbenratzlaff

But why is

M.displayObjectGroup[i] = nil

not the same thing as

M.starTable.starText = nil

when “M.starTable.starText” is in the group? I would have assumed that both the statements above remove the exact same data.

The code was just an example, the real module is much more complex and M.starTable is used in a lot of places.

First, this is a variable

M.starTable.starText

Assigning nil to it will nil the ‘variable’ so it doesn’t reference anything.

Second, you’re misunderstanding the concept.  ‘nil’ has no effect on the object itself.  The purpose of ‘nilling’ references is to ensure no variable holds a reference to the object so Lua can remove the object.  

‘nilling’ == clearing (a variable)

Lua knows if there are references to an object and until they are all cleared, the object will stay in memory.

Third, VERY IMPORTANT, this code is completely wrong and dangerous:

M.displayObjectGroup[i] = nil

If ’ displayObjectGroup’ is an actual display group, you never want to assign to a child index. I honestly don’t know what that will do, but it won’t be good.

When you remove an object using display.remove() or obj:removeSelf(), it is AUTOMATICALLY removed from the group that owns it and that group AUTOMATICALLY clears its reference to that object.

The ONLY reason to ever use a child index to reference an entry in a group is to operate on the object at that index.  NEVER EVER assign to a child index of a display group.

Oh, and if ‘displayObjectGroup’ is just a table, then using the word ‘group’ in the name is just bad practice and super confusing.

@roaminggamer

displayObjectGroup is actually table, not a display group. I agree, a really poor naming choice. Sorry about the confusion…

Given that, I follow the docs for removing display objects (https://docs.coronalabs.com/api/type/DisplayObject/removeSelf.html)

using both :removeSelf() and nilling. However, the docs also say this:

What remains of the object is simply a plain Lua table with all non-display object properties — the metatable is set to nil and all properties relating to display object are removed. Thus, if there are still references to object in Lua, they will simply be references to a normal Lua table.

In other words, testing for nil as I do in my first posting:

if (M.starTable.starText ~= nil) then --- end

will not work. So, the question remains: how can I see if a display object exists or not?

I probably won’t be able to help without seeing all of the code, but I don’t really want to… so let me suggest what I always suggest.

Never use numerically indexed tables to store references to display objects unless you absolutely need to know the order they were created in.

I always do this instead:

local myObjects = {} ... then later local function onTouch( self, event ) if( event.phase == "ended" ) then myObjects[self] = nil -- Clear entry indexed by this object in table display.remove(self) -- remove object (done; it will now free) end return false end -- Randomly place 10 circles and attach common touch listener. for i = 1, 20 local tmp = display.newCircle( math.random( 100, 400 ), math.random( 100, 400 ), 10 ) myObjects[tmp] = tmp tmp.touch = onTouch tmp:addEventListener( "touch" ) end -- Now, touching the circles removes them and cleans their references. Easy-Peasy

Also, if you’re using multiple variables to reference the same object and those variables are global or file-level in scope… 

This is kind-of a bad practice as you’ve discovered.  

That said, if you keep objects in a ‘object’ indexed table you can do this:

myObjects[M.starTable.starText] = nil -- clear the table entry/reference display.remove(M.starTable.starText) -- remove the object M.starTable.starText = nil -- clear the variable

As far as, checking if an object exists?  If you mean, “How do I check whether I cleared all references to it?”

The simple answer is, you can’t (easily do this).  You’re better off simplifying your code to have as few references to the same object as possible.

However, if you meant, “I have a reference to an object.  How do I check to see if that reference is pointing to a valid display object or a table stub?”

There are several ways, but one of the most robust I know is:

local objRef = display.newCircle( 10, 10, 10 ) print( "Is Valid? ", (objRef.removeSelf ~= nil and type(objRef.removeSelf) == "function" ) ) display.remove( objRef ) print( "Is Valid? ", (objRef.removeSelf ~= nil and type(objRef.removeSelf) == "function" ) )

Prints: 

Is Valid? true Is Valid? false

@roaminggamer

Again, thank you very much for your answers.

The whole reason I’m using a table to store all display objects is to be able to delete them all when switching from one scene to another. I know composer does that for me but I do not use composer in this app (rookie mistake, long story). So, each display object created is put in displayObjectGroup and when switching to another scene I simply delete them all by

 for i = 1, #M.displayObjectGroup do     M.displayObjectGroup[i]:removeSelf()      M.displayObjectGroup[i] = nil  end

Given this, would you use an indexed table to keep track of all display objects like I do or is there a better solution (apart from using composer, which I do in my newer apps)?

You mention “multiple variables to reference the same object”. Am I doing that? If you look in my original post, isn’t M.starTable.starText the only reference to the text object? Or does putting it in an indexed table itself create another reference to it?

Regarding your last post, I assume object.removeSelf means the function object:removeSelf() and if I understand your code correctly that function becomes nil after the object is removed and the variable is nilled? Is that correct?

  1. Use an actual display group and remove the display group.  This will automatically delete its children.

    – At start of scene/game/level/… local group = display.newGroup() – Now add objects directly when you make them: local someVar = display.newCircle( group, 10, 10, 10 ) display.newRect( group, 10, 10, 10, 10 ) – … etc … – Later: display.remove( group ) – I NEVER use removeSelf() it is unsafe if you goof up and call it twice. group = nil someVar = nil – At this point, the objects are all removed. Now, as long as all reference variables are cleared – or as long as they fall out of scope and are automatically removed by Lua, the – objects will be garbage collected.

  2. multiple variables/references - Yes you are.  The table entries are a ‘reference’ too.

  3. re: your last question yes.  You’re checking if the ‘Corona stuff’ has been stripped off the reference/object.  If it is gone, then the reference is to a stub.