Posted on by
NOTE: This tutorial is outdated. For current information, please refer to the Introduction to Lua guide or watch the Variables and Scope videos.

Posted by . Thanks for reading...

22 Responses to “The Significance of Local Variables in Lua”

  1. Rob Miracle

    Thanks Jonathan. This is very helpful.

    Two questions, one kind of unrelated.

    First, consider this block of code, assume it’s in the main chunk:
    local x = 1
    local y = 2
    local z = “Fred”

    vs.

    local t = { x=1, y=2, z=”Fred” }

    Is there a performance hit by putting variables in a table like that?

    My second question which is kinda of not releated:

    What is the difference between:

    local function myFunction() … end and
    local myFunction = function() … end

    Reply
  2. Alberto

    Hey Jonathan, good read as always. In general using local variables is a good practice both for speed and keeping your code more organized but I wonder about the need to further localize local variables. In the examples above you are creating new local variables to optimize access to an already local variable for use within an inner loop. I wonder how the overhead of creating a new variable compares to having to access a local variable in the scope right above as there wouldn’t be much “searching” going on unless you have a ton of locals.

    So if this comment is to have a point, it is to highlight the need for a Corona Profiler where an article like this could empirically demonstrate the performance gains of this approach. To quote Donald Knuth’s famous line “Premature optimization is the root of all evil”.

    Reply
  3. Jonathan Beebe

    @Rob: There’s not a lot of literature that states whether or not a plain local variable is quicker than accessing a key in a local table. I’m assuming that a plain local variable would be quicker, but probably not by enough to even matter.

    I have read in plenty of places, however, that defining functions like so:

    local myFunction = function()

    Yields better performance than:

    local function myFunction()

    However, keep in mind that if you need your function to call itself, you cannot define it in the first method above. Most functions, however, can benefit from being defined in that way.

    @Alberto: Great point! In the small examples I gave above, you’re right, it doesn’t make hardly any difference (if any difference) at all. The point is just to get in a habit of localizing your variables, and localizing as far as you can because it can make a difference if your app had tons of enterFrame listeners going on, and you have to squeeze as much performance as you can from your app … it theoretically could make some kind of positive impact.

    Most importantly, the habit of doing that alone could prevent any stray globals from slipping their way in there.

    Another benefit to re-localizing locals (that you do not need to modify the value of), is that you can prevent yourself from accidentally changing the value of an upvalue if you didn’t intend to do that to begin with.

    Recently, I came across that situation myself. There was a local upvalue that I was referencing in another code block. At some point during the development process, I needed that code block to modify the value of that variable, but only in that code block. Because I did not re-localize the local (store a copy of it for use in that code block), whenever that block was called it actually changed the value of the local upvalue, which resulted in a pretty nasty bug.

    Thanks again for your comments everyone, keep them coming!

    Reply
  4. David

    Good article. Lua definitely has its caveats! For example, different rules when using local tableVar than local otherVar. That’s great to know, but not really a logical rule.

    Also, had a question for you Jonathan. In your first example of code to consider, you wrote this:
    1 local myTable = { 1, 2, 3, 4, 5 }
    2
    3 local printThird = function()
    4 local t = myTable
    5 print( t[3] )
    6 end

    My question is: Why is it any faster to reference the global variable on line 4 than it is on line 5? If Lua knows where to get the variable to localize it on line 4, logically it should also be just as quick to find it for printing on line 5. Why is that?

    Lovin’ Corona. Keep up the great work!

    Thanks,
    David

    Reply
  5. Simon

    Hi Jonathan,

    Thank you for this post. I was just wondering if you have any benchmarks in terms of HOW much faster is using a local vs global variable?

    Thanks,
    Simon

    Reply
  6. Jonathan Beebe

    @David: Great point! I should have added that it’s really only viable if you use the variable at least a few times, because otherwise you’re right, you’re doing the same exact thing for lookup.

    I mentioned that the examples themselves are fairly pointless, but in practice within a real project, the tips could mount up to a positive impact. I was mainly showing how to localize further, because the words might not actually describe it very well. I’ll definitely have to add in something that shows it being useful for multiple lookups in the same code block.

    Thanks for pointing that out!

    Reply
  7. Jon

    Great article, however I’d like to clarify a small point with regards to the “For all other things (… and functions), a copy is made and stored in the local variable”, the wording implies that a “copy” of the function is made, i.e. a new block of ram is allocated and the contents of the function copied in to it, although I suspect it’s just a “reference” (or for all you C/C++ programmers out there – a “pointer”) to the function that’s copied across (which would seem to make more sense) – any chance any one can clarify that?

    Also – I was under the impression that

    local myFunction() … end

    was just “syntactic sugar” for

    local myFunction = function() … end

    I can’t see any reason why one version would give better performance than the other – especially if the lua script was “compiled” into byte code before running anyway, is there any chance you could post some links to any discussions on the topic?

    Keep up the good work!

    Reply
  8. Brent

    Hi Jon,
    Thanks for this great article. I’m a stickler for optimization even after I have optimized quite alot, and so I’m going to implement this “deeper localization” in some of my heavier game functions.

    I would, however, like to hear more about the impact of:

    local function myFunction() … end
    VS.
    local myFunction = function() … end

    I have always used the former syntax because I find it easier to read in code, and also in the XCode Editor (my core development editor) it populates the drop-down function menu with a list of these functions, so I can easily locate them within a 500-1000+ line project. The latter syntax does not do this. :(

    Even if the latter syntax is somewhat faster, what kind of real-world performance would this have in 95% of instances? In most cases, I call a function once in a cycle to perform whatever the function was written for, i.e. “local function dropBomb()” drops a bomb. ;) If this function gets called occasionally (say once per second or less), I imagine the lookup is quite fast and we would barely notice a performance boost by doing it the other way. The exception, I would guess, is if you call a function many many times in a sequence, i.e. if you call “dropBomb” in a loop of 1 to 100 to drop 100 bombs. THEN we might see a benefit from the other method.

    As Jon (the other Jon) requested, do you have some links to articles about these two syntax uses and the benefits of the latter?

    As always, thanks for your continued help and ongoing support in the Corona community!
    Brent

    Reply
  9. Brent

    Another quick question…

    If you create a local “pointer” to a table, as follows:

    local enemies = {}
    local function newEnemy()
    local enemies = enemies
    –(loop of 10)
    local thisEnemy = (Corona display object)
    enemies[#enemies+1] = thisEnemy
    –(end loop)
    enemies = nil
    end

    Not the greatest example, but the point is, a “deep” local variable is created to REFERENCE the storage table “enemies”. The local reference is named the SAME as the “upvalue” name, which seems to cause no problems whatsoever.

    My question is, in the last line of the function, can I forcibly “nil” this local reference out so it’s cleared from memory? I assume that Lua will only ‘nil out the REFERENCE and NOT the actual table (upvalue) that it’s pointing to? What I mean is, does Lua recognize that there’s a deeper local reference at this scope and target ONLY that one for deletion?

    Brent

    P.S. – I’m aware that in this example it doesn’t make much sense to forcibly “nil” this reference out; you’d say just let it be garbage-collected. But since this article is about syntax, not necessarily “best practice”, I’d like to confirm this methodology.

    Reply
    • Jonathan Beebe

      Great question! When it comes to local variables that act as references to other tables/variables/etc, nil’ing out the local variable does not actually set the original to nil. It simply clears the local variable from memory. When it comes to tables, THAT is the only thing that modifying the local variable doesn’t actually modify the original. I should definitely add that into the article somewhere as it is very important. Thanks for pointing that out!

      Reply
  10. Thorbjørn Lindeijer

    I think explanation of the difference between “reference” and “copy” here is misleading. For sure strings and functions are also referenced objects. There just doesn’t happen to be a way to modify those objects like you can with tables. The following shows there is really no difference:

    local i = 10
    local f = function() end
    local s = “foo”
    local t = {}

    print(i, s, f, t)

    local function bar()
    local i, f, s, t = i, f, s, t
    i = 20
    f = function() end
    s = “zoo”
    t = {}
    end

    bar()

    print(i, s, f, t)

    The above does not yield an new table ‘t’ outside of the function ‘bar’ any more than it yields a ‘i’ with value 20, but only the number in ‘i’ was really copied while the rest are copied references.

    The difference is not in whether the value is copied or not. What makes the table unique is that it allows the referenced contents to be modified.

    Reply
    • Jonathan Beebe

      Thanks for pointing that out. I wasn’t meaning to say it is an “actual copy”, but rather emphasis the behavior (since most people are familiar with the behavior of a copy). Nevertheless, I’ve updated the article to be more technically correct while still preserving it’s meaning. Thanks again :-)

      Reply
  11. Alberto

    Another thing to consider when applying localizing local variables a second time as a general practice is to understand the tradeoff. You’re exchanging speed for memory which might be the intent, unless you are trying to optimize your memory footprint. So without tools like a profiler and memory analyzer or your own custom code to measure the impact I probably wouldn’t do this for everything I write.

    Reply
  12. Brent

    Hi Jon,
    Have you researched Lua performance when it comes to *passing* variables to a function VS. *localizing* variables?

    Take the following example:

    —–

    local forwardValue = 50

    local function putObjects_Passed ( passedValue )
    –BIG LOOP using “passedValue” (=forwardValue)
    end
    putObjects_Passed ( forwardValue )

    local function putObjects_Localized ()
    local val = forwardValue
    –BIG LOOP using local “val” (=forwardValue)
    end

    —–

    Obviously the difference is, in the first function the variable “forwardValue” is being passed to the function as a parameter/value. Then the loop uses this value repeatedly. The up-value lookup is only done once, presumably, when the function is first called.

    In the second function, the local variable “val” up-values “forwardValue” and the loop uses that local variable. Likewise with #1, the up-value lookup is only done once, before the loop begins.

    Any idea which of these functions might be faster? Is there any way I can test them, in fact? Some program in XCode that I might plug these functions into and see how many milliseconds it took to perform each one? Similar to that great website you gave on Lua Performance tricks, where they sample different methods in a massive loop of 1 to 1000000 and get a percentage… that’s what I’d like to test with these two functions. :)

    Thanks,
    Brent

    Reply
  13. john

    Hi everyone,
    I am having such a hard time with declaring global and local variables. I believe it’s because that I am used to visual basic such that if you create a global variable you can access it anywhere in the program. ( I read the forum, can’t figure it out). In the sample code below I have some ui buttons created (code not shown for UI buttons) and I assigned them letters which are being shuffled. The touch function/event works fine, however when I try to access the variables “finalshuffled”, “reshuffledList” outside of the functionfor some reason I just keep getting “nil value” . How can I declare those variables so that I can access them/their values anywhere in the programs. I tried with/out “local” and I tried _G nothing seems to work. Thank you for the help.

    Sample touch event code:

    function button1:touch(event)

    function shuffle( a )
    local c = #a
    for i = 1, c do
    local ndx0 = math.random( 1, c )
    a[ ndx0 ], a[ i ] = a[ i ], a[ ndx0 ]
    end
    return a
    end

    local list = {“T”, “T”, “T”, “T”, “T”, “T”, “T”, “T”, “T”, “T”};
    local shuffledList = shuffle(list)

    print(table.concat(shuffledList, “,”))

    allLetters =display.newText(table.concat(shuffledList, “,”) ,200,200,native.systemFont,35)

    reshuffledList=print (allLetters.text:sub(1,9)) — This crate a unique list of 5 letters

    finalshuffled = display.newText(allLetters.text:sub(1,9),50,50,native.systemFont,35)

    local Word= display.newText(” “,134,407,native.systemFont,35)

    local isinlist =print(string.find(allLetters.text:sub(1,9), “button1:setText(Word.text:sub(1,1))”, 1))

    if isinlist == nil then

    local r2=math.random(0,4)
    if r2==0 then
    guessbutton1:setText(” “)
    guessbutton1.text=button1:setText(Word.text:sub(1,1))
    elseif r2==1 then
    guessbutton2:setText(” “)
    guessbutton2.text=button1:setText(Word.text:sub(1,1))
    elseif r2==2 then
    guessbutton3:setText(” “)
    guessbutton3.text=button1:setText(Word.text:sub(1,1))
    elseif r2==3 then
    guessbutton4:setText(” “)
    guessbutton4.text=button1:setText(Word.text:sub(1,1))
    elseif r2==4 then
    guessbutton5:setText(” “)
    guessbutton5.text=button1:setText(Word.text:sub(1,1))

    end

    end

    guessbutton1:setText(finalshuffled.text:sub(1,1))
    guessbutton2:setText(finalshuffled.text:sub(3,3))
    guessbutton3:setText(finalshuffled.text:sub(5,5))
    guessbutton4:setText(finalshuffled.text:sub(7,7))
    guessbutton5:setText(finalshuffled.text:sub(9,9))

    end

    button1:addEventListener (“touch”, button1)

    I tried to call reshuffledList in the code below (outside of the touch event function) and it give me a Nil value

    guess1text=guessbutton1:setText(finalshuffled.text:sub(1,1))
    print (guessbutton1:setText(finalshuffled.text:sub(1,1)))
    print(guess1text)

    The print function above should print the letter “T” , however, it given me a nil value.

    Reply

Leave a Reply

  • (Will Not Be Published)