TheyNeedToBeFed Question

Hi,

I guess this question is for Ed, but Id be happy for anyone to answer.

I am going through the “TheyNeedToBeFed” code trying to understand how it works (great way of learning new techniques etc).  I have one quick question.

In inputs.lua in the destroy method you ‘nil’ out leftbutton, rightbutton etc to clean up local variables, which I understand.  However, these variables were made at the file level and it is my understanding that modules are only loaded once (maybe I got the wrong end of the stick here), therefore, once these variables are nil’ed out the next time they are used they would not have been created at a file level and therefore become global?

Am I missing something?  Thanks,  I am just trying to understand the logic behind things.

Cheers,

Craig

  1. Yes, modules are loaded only once,  unless you unrequire() them which is an advanced technique and not part of normal Lua.
     

  2. I nil them out here:

    function inputs.destroy() leftButton = nil rightButton = nil jumpButton = nil fireButton = nil end

 3. I do this, to future proof this process:

  • Load inputs.lua moduile

  • Create layers

  • Create inputs.

  • Destroy layers (destroys input objects automatically, but leaves references behind in these variables:

    local leftButton local rightButton local jumpButton local fireButton

It is worth noting this simply allows for proper garbage collection,  however,  at this point, I could re-create the layers and call inputs.create() again.  As soon as this completed, the original references would be gone and garbage collecting could occur.
 
So, the short of it is, I did this because it is a good idea to have a destroy/cleanup process and to nil dangling referenced to destroyed Corona objects.  It really doesn’t get used in my demo, but it is there if you need it.
 
:slight_smile:
 
PS - That part about becoming global is not right.  Those variables will always be local and visible in the scope of that file ONLY.  Thus calling create more than once doesn’t change the visibility of leftButton, rightButton, etc…

Also, nilling a local does not remove the local, it clears the reference in the local.

Awesome.  Once again thanks Ed…

Hi Ed,  

Can you possibly explain what you mean by “Also, nilling a local does not remove the local, it clears the reference in the local.”.

Cheers,

Craig

When you declare a local that local stays around forever till it falls out of scope. 
 
There are several scope types but two common ones are:

  • file-level - Throughout whole file after line of (the local’s) declaration.

function/method level - Within the body of a function/method after line of (the local’s) declaration.

Example. The following should be considered to be a module saved in a file called “myModule”:

local public = {} -- Two local variables with file-level scope (never destroyed unless module is unloaded). local var1 = 50 local var2 = display.newCircle( 10, 10, 10 ) -- dumb, but hey its an example of syntax... function public.doit1() -- This removes the circle object refered to by var2 and nils var2 so that -- the left-over Lua stub object (a table) cab be garbage collected display.remove( var2 ) var2 = nil -- At this point, var2 exists, but is empty (refers to nothing) -- Now I make a new circle stored in var2 (var2 IS NOT GLOBAL) -- var2 = display.newCircle( 10, 10, 10 ) end function public.doit2() -- Creates two function-level locals -- local var1 = 10 -- This local has the same name as the file-level one. It does not replace it. -- Instead, the new one is used till it goes out of scope local var3 = 12 print( var1, var3 ) -- Always prints: 10 12 -- When this is called, as soon as 'end' is reached, -- the function-level locals: var1, var3 are destroyed. end function public.doit3() This prints the file-level scope var1 print( var1 ) -- Always prints: 50 end return public 

Now, doing this:

local myModule = require "myModule" myModule.doit2() myModule.doit3() myModule.doit2() myModule.doit3()

prints:

10 12 50 10 12 50

For more on this. Read through the Lua PIL. This is all Lua stuff, not really Corona specific.

http://www.lua.org/pil/

Thanks. I was confused about the nil’ing of variables, I thought that completely removed it. Your example has made it much clearer, thanks again. Craig

Hi Ed, should the output from myModule.doit3() not be 50 rather than 20? At the top of the module var1 is set to 50, and I don’t see that it’s edited any where. 

Just thought I’d mention it in case it confuses people looking at this later.  :slight_smile:

this is just pointless nitpicking, so apologies, but lua really has only two scopes:  global and block.  anything declared with “local” becomes local to the environment of the block in which is it declared, anything declared without “local” ends up in the global environment - it’s really just that simple.

tho two things potentially complicate that simple understanding:

  1. “blocks” may be formed in numerous (maybe unexpected) ways:  a chunk of code loaded w require, a function or closure, a do-end, a for loop, etc – but they’re all really the same (just blocks) as far as “where” the local is scoped.

  2. global variables don’t need explicit declaration, an assignment will implicitly declare them (fe if “x” is not already a local, then “x=10” implicitly declares x as a global and assigns it the value 10).  so you can be deep within a nested block scope (a for loop within a function within a module, etc) and “accidentally” declare a global (a common “gotcha” is to typo an intended local variable name, thus creating a new accidental global).  otoh, locals must be explicitly declared, and it should be obvious why - the “location” of the keyword “local” establishes which block environment it is scoped within

advanced weirdness:  even if you get really screwy and mess with setting your own environments, the same two types of scope still exist - just using your own environment instead of the default one.  (doubt many corona users ever do this tho)

My bad.  I updated that example at the last second and didn’t double check.

  1. Yes, modules are loaded only once,  unless you unrequire() them which is an advanced technique and not part of normal Lua.
     

  2. I nil them out here:

    function inputs.destroy() leftButton = nil rightButton = nil jumpButton = nil fireButton = nil end

 3. I do this, to future proof this process:

  • Load inputs.lua moduile

  • Create layers

  • Create inputs.

  • Destroy layers (destroys input objects automatically, but leaves references behind in these variables:

    local leftButton local rightButton local jumpButton local fireButton

It is worth noting this simply allows for proper garbage collection,  however,  at this point, I could re-create the layers and call inputs.create() again.  As soon as this completed, the original references would be gone and garbage collecting could occur.
 
So, the short of it is, I did this because it is a good idea to have a destroy/cleanup process and to nil dangling referenced to destroyed Corona objects.  It really doesn’t get used in my demo, but it is there if you need it.
 
:slight_smile:
 
PS - That part about becoming global is not right.  Those variables will always be local and visible in the scope of that file ONLY.  Thus calling create more than once doesn’t change the visibility of leftButton, rightButton, etc…

Also, nilling a local does not remove the local, it clears the reference in the local.

Awesome.  Once again thanks Ed…

Hi Ed,  

Can you possibly explain what you mean by “Also, nilling a local does not remove the local, it clears the reference in the local.”.

Cheers,

Craig

When you declare a local that local stays around forever till it falls out of scope. 
 
There are several scope types but two common ones are:

  • file-level - Throughout whole file after line of (the local’s) declaration.

function/method level - Within the body of a function/method after line of (the local’s) declaration.

Example. The following should be considered to be a module saved in a file called “myModule”:

local public = {} -- Two local variables with file-level scope (never destroyed unless module is unloaded). local var1 = 50 local var2 = display.newCircle( 10, 10, 10 ) -- dumb, but hey its an example of syntax... function public.doit1() -- This removes the circle object refered to by var2 and nils var2 so that -- the left-over Lua stub object (a table) cab be garbage collected display.remove( var2 ) var2 = nil -- At this point, var2 exists, but is empty (refers to nothing) -- Now I make a new circle stored in var2 (var2 IS NOT GLOBAL) -- var2 = display.newCircle( 10, 10, 10 ) end function public.doit2() -- Creates two function-level locals -- local var1 = 10 -- This local has the same name as the file-level one. It does not replace it. -- Instead, the new one is used till it goes out of scope local var3 = 12 print( var1, var3 ) -- Always prints: 10 12 -- When this is called, as soon as 'end' is reached, -- the function-level locals: var1, var3 are destroyed. end function public.doit3() This prints the file-level scope var1 print( var1 ) -- Always prints: 50 end return public 

Now, doing this:

local myModule = require "myModule" myModule.doit2() myModule.doit3() myModule.doit2() myModule.doit3()

prints:

10 12 50 10 12 50

For more on this. Read through the Lua PIL. This is all Lua stuff, not really Corona specific.

http://www.lua.org/pil/

Thanks. I was confused about the nil’ing of variables, I thought that completely removed it. Your example has made it much clearer, thanks again. Craig

Hi Ed, should the output from myModule.doit3() not be 50 rather than 20? At the top of the module var1 is set to 50, and I don’t see that it’s edited any where. 

Just thought I’d mention it in case it confuses people looking at this later.  :slight_smile:

this is just pointless nitpicking, so apologies, but lua really has only two scopes:  global and block.  anything declared with “local” becomes local to the environment of the block in which is it declared, anything declared without “local” ends up in the global environment - it’s really just that simple.

tho two things potentially complicate that simple understanding:

  1. “blocks” may be formed in numerous (maybe unexpected) ways:  a chunk of code loaded w require, a function or closure, a do-end, a for loop, etc – but they’re all really the same (just blocks) as far as “where” the local is scoped.

  2. global variables don’t need explicit declaration, an assignment will implicitly declare them (fe if “x” is not already a local, then “x=10” implicitly declares x as a global and assigns it the value 10).  so you can be deep within a nested block scope (a for loop within a function within a module, etc) and “accidentally” declare a global (a common “gotcha” is to typo an intended local variable name, thus creating a new accidental global).  otoh, locals must be explicitly declared, and it should be obvious why - the “location” of the keyword “local” establishes which block environment it is scoped within

advanced weirdness:  even if you get really screwy and mess with setting your own environments, the same two types of scope still exist - just using your own environment instead of the default one.  (doubt many corona users ever do this tho)