Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Stupid Lua question — Gideros Forum

Stupid Lua question

john26john26 Maintainer
edited June 2014 in General questions
Here's something that's been bugging me. If I do

local a=1
local a

What happens? Is the second local a ignored? Does it create a new variable? It does not cause a crash and nothing "bad" seems to happen.

This sort of "mistake" can happen when the two "local a" statements are in the same block but separated by lots of code. The PIL seems to say nothing about this.

Comments

  • edited June 2014 Accepted Answer
    I asked on irc about this.

    Seemly it is legal code, and what it do is create a new variable named a, and it hides (not delete) the old one.

    if you do:

    local a=1;
    print(a);
    local a;
    print(a);

    it will print:

    1
    nil
    I make games for children: http://www.kidoteca.com
  • john26john26 Maintainer
    edited June 2014
    Yes, I got the same result. But what happens to the hidden one. Does it mean tables cannot be garbage collected?
  • HubertRonaldHubertRonald Member
    edited June 2014

    local a=1
    local a
    Hi @john26
    I think the same as @speeder_kidoteca, This is a way to restart the local variable, I also got the same results as @speeder_kidoteca.
    local a=1; print(a) --->> 1
    local a; print(a)  --->> nil
    P.S I used the compiler iLua Version 1.0.4, 2010
  • edited June 2014
    john26

    they will be garbage collected once out of scope.
    they are not immediately erased to don't break tables that have multiple names
    ie:

    if you do

    local a=someOtherTable;
    local a;

    If we just deleted the first A outright, we might end accidentally deleting the "someOtherTable" thus a (the first) is only hidden.
    I make games for children: http://www.kidoteca.com
  • john26john26 Maintainer
    Thanks, all for your answers. To make it more concrete, in the context of Gideros, here's a real world example of accidentally redefining a local in same scope.
    function Score:init(col1,col2)
     
       local w,h=40,40
     
       self[1]=0
       self[2]=0
     
       local r=Shape.new()
       r:setFillStyle(Shape.SOLID,col1)
       r:setLineStyle(2,0)
       r:beginPath()
       r:moveTo(-w/2,-h/2)
       r:lineTo( w/2,-h/2)
       r:lineTo( w/2, h/2)
       r:lineTo(-w/2, h/2)
       r:closePath()
       r:endPath()
     
       local t=TextField.new(font40,"0")
       centreAt0(t)
     
       local b=Sprite.new()
       b:addChild(r)
       b:addChild(t)
       b:setPosition(40,0)
       self:addChild(b)
     
    ---------------------------
     
       local r=Shape.new()
       r:setFillStyle(Shape.SOLID,col2)
       r:setLineStyle(2,0)
       r:beginPath()
       r:moveTo(-w/2,-h/2)
       r:lineTo( w/2,-h/2)
       r:lineTo( w/2, h/2)
       r:lineTo(-w/2, h/2)
       r:closePath()
       r:endPath()
     
       local t=TextField.new(font40,"0")
       centreAt0(t)
     
       local b=Sprite.new()
       b:addChild(r)
       b:addChild(t)
       b:setPosition(-40,0)
       self:addChild(b)
    end
    Notice the code after the "---" is almost the same so I just cut and pasted it from the first chunk. My intention was to reuse the "r", "t" and "b" variables, but I have ended up redefining them as new locals which hide the old versions of "r, t, b".

    In this case, it seems, no harm is done. There are two versions of "r" etc and both point to different tables in memory. When the function returns, both "r"'s will be destroyed but, since I have used addChild, references are held to these tables and they will (correctly) not be garbage collected.

    So it seems no harm is done, but can you think of a case where this might result in a memory leak? Personally, I think this is an oddity of Lua. Redefinition should result in a run time error IMO.

    Likes: hgvyas123

    +1 -1 (+1 / -0 )Share on Facebook
  • HubertRonaldHubertRonald Member
    edited June 2014
    Hi @john26
    Thanks for share

    I wanted to reflect on what you have posted and I wrote the following code, for I am also looking for memory leak in my application
    local function collect()
    	collectgarbage("collect")
    	collectgarbage("collect")
    	collectgarbage("collect")
    	collectgarbage("collect")
     
    	collectgarbage("stop")
    	collectgarbage("stop")
    	collectgarbage("stop")
    	collectgarbage("stop")
     
    end
     
     
    local function report(num)
    	print(
    			"Memory Step "..num,
    			"luaMem: "..math.ceil(collectgarbage("count"))/(1000),
    			"Mb textureMem: "..math.ceil(application:getTextureMemoryUsage())/(1000).."Mb"
    			)
    end
     
    print(""); report(1)
    for i=1, 100*100 do
    	local b=Sprite.new()
    	stage:addChild(b)
    end
    report(2); collect(); report(3)
     
    while stage:getNumChildren()~=0 do
    	stage:removeChildAt(1)
    end
    report(4); collect(); report(5)
     
    --[[
    -- my summary
    Memory Step 1	luaMem: 0.088	Mb textureMem: 0Mb
    Memory Step 2	luaMem: 1.555	Mb textureMem: 0Mb
    Memory Step 3	luaMem: 1.555	Mb textureMem: 0Mb
    Memory Step 4	luaMem: 1.555	Mb textureMem: 0Mb
    Memory Step 5	luaMem: 0.462	Mb textureMem: 0Mb
    ]]
    and memory goes from 0.088Mb to 0.462Mb
    why? I don't know

    Also I tried to see if changed some in global variables (before and after) with this code
    for k,v in pairs(_G) do
    	print(k,v)
    end
    and nothing :-?

    But see this post
    http://giderosmobile.com/forum/discussion/799/addingremoving-children-and-memory-usage/p1

    and if you change above code
    print(""); report(1)
    local a=Sprite.new()
    for i=1, 100*100 do
    	local b=Sprite.new()
    	a:addChild(b)
    end
    stage:addChild(a)
    report(2); collect(); report(3)
     
    a:removeFromParent()
    ---------------------------------
    a=nil  ------>>>"THE KEY IS HERE"
    ---------------------------------
    report(4); collect(); report(5)
    --[[
    -- my summary
    Memory Step 1	luaMem: 0.088	Mb textureMem: 0Mb
    Memory Step 2	luaMem: 1.556	Mb textureMem: 0Mb
    Memory Step 3	luaMem: 1.556	Mb textureMem: 0Mb
    Memory Step 4	luaMem: 1.556	Mb textureMem: 0Mb
    Memory Step 5	luaMem: 0.078	Mb textureMem: 0Mb
    ]]
    in this case use of memory down (from 0.088Mb to 0.078Mb )

    I think all this is summed up, as you administer local variables to avoid memory leaks, if you you can have them assigned "nil" to local variables defined before, then you can save Memory.

    Likes: hgvyas123

    +1 -1 (+1 / -0 )Share on Facebook
  • john26john26 Maintainer
    edited June 2014
    I think in the first case, stage still has 10,000 nil references. Its like saying

    a={}
    a[1]={1,2,3}
    a[2]={4,5,6}

    a[1]=nil
    a[2]=nil

    The tables {1,2,3} and (4,5,6} can now be garbage collected but a is still a table with entries "1" and "2". I don't think Lua deletes variables which are nil.

    But your loop with a local in it worries me as well.
    for i=1, 100*100 do
    	local b=Sprite.new()
    	stage:addChild(b)
    end
    following the previous discussion, when the loop iterates is a new version of "b" generated which hides the previous one? That would mean 10,000 copies of b are created all of which are deleted when the loop ends. That seems crazy! Lua should try to reuse variables in the same scope.
  • tkhnomantkhnoman Member
    edited June 2014
    Hmmm...
    local a = 1
    while true do
    	local name, value = debug.getlocal(1, a)
    	if not name then break end
    	print(name, value)
    	a = a + 1
     end

    Put this code to debug the local. When you define 2 b, you can see 2 b.
    The holder is something else, not "b" itself.

    :-?
  • HubertRonaldHubertRonald Member
    edited June 2014
    I think in the first case, stage still has 10,000 nil references. Its like saying

    a={}
    a[1]={1,2,3}
    a[2]={4,5,6}

    a[1]=nil
    a[2]=nil

    The tables {1,2,3} and (4,5,6} can now be garbage collected but a is still a table with entries "1" and "2". I don't think Lua deletes variables which are nil.

    Oh! This made me remember a previous post of mine
    http://giderosmobile.com/forum/discussion/comment/35572#Comment_35572

    I extrapolated your example and I got the following
    --[[
    ----------------------
    Functions defined above
    ----------------------
    report(num)
    collect()
    ]]
    print(""); report(1)
    a={}
    for i=1, 100*100 do
    	a[#a+1]={1,2,3}
    end
    report(2); collect(); report(3)
     
    for i=1, 100*100 do
    	a[i]=nil
    end
    report(4); collect(); report(5)
    print("len table a:",#a)
    a=nil
    collect(); report(6)
     
    --[[
    -- my summary
    Memory Step 1	luaMem: 0.088	Mb textureMem: 0Mb
    Memory Step 2	luaMem: 0.909	Mb textureMem: 0Mb
    Memory Step 3	luaMem: 0.909	Mb textureMem: 0Mb
    Memory Step 4	luaMem: 0.91	Mb textureMem: 0Mb
    Memory Step 5	luaMem: 0.207	Mb textureMem: 0Mb
    len table a:	0
    Memory Step 6	luaMem: 0.079	Mb textureMem: 0Mb
    ]]


    But your loop with a local in it worries me as well.
    for i=1, 100*100 do
    	local b=Sprite.new()
    	stage:addChild(b)
    end
    I know than Lua 2 Tips, it suggests you than you must not to define local variables inside "for" loop because is not fast... but now I see than it also has a cost in Lua Memory.
  • Hmmm...
    local a = 1
    while true do
    	local name, value = debug.getlocal(1, a)
    	if not name then break end
    	print(name, value)
    	a = a + 1
     end

    Put this code to debug the local. When you define 2 b, you can see 2 b.
    The holder is something else, not "b" itself.

    :-?
    Hi @tkhnoman

    In this site I've seen as you can print all local variables
    http://stackoverflow.com/questions/2834579/print-all-local-variables-accessible-to-the-current-scope-in-lua
Sign In or Register to comment.