6

How is it possible that this piece of code:

local t
for n = 0, 255 do
    t = math.random(0, 255)
    ...
end

Is actually slower than this one?

for n = 0, 255 do
    local t = math.random(0, 255)
    ...
end

Since I am accessing t more than once in the ... part, I am wondering, do for loops have their own set of local variables? If yes, is accessing a local variable from the current block faster than accessing one from the outer block?

user6245072
  • 2,051
  • 21
  • 34

1 Answers1

7

In general, declare variables as local as possible. And yes, for loop makes its own scope. It's the better coding style, and, as this example shows, usually more optimized.

Let's see what instructions the two pieces of code are generating, with luac -l

The first piece:

main <t.lua:0,0> (13 instructions at 00000000005e8260)
0+ params, 8 slots, 1 upvalue, 5 locals, 5 constants, 0 functions
        1       [1]     LOADNIL         0 0
        2       [2]     LOADK           1 -1    ; 0
        3       [2]     LOADK           2 -2    ; 255
        4       [2]     LOADK           3 -3    ; 1
        5       [2]     FORPREP         1 6     ; to 12
        6       [3]     GETTABUP        5 0 -4  ; _ENV "math"
        7       [3]     GETTABLE        5 5 -5  ; "random"
        8       [3]     LOADK           6 -1    ; 0
        9       [3]     LOADK           7 -2    ; 255
        10      [3]     CALL            5 3 2
        11      [3]     MOVE            0 5
        12      [2]     FORLOOP         1 -7    ; to 6
        13      [4]     RETURN          0 1

The second piece:

main <t.lua:0,0> (11 instructions at 0000000000538260)
0+ params, 7 slots, 1 upvalue, 5 locals, 5 constants, 0 functions
        1       [1]     LOADK           0 -1    ; 0
        2       [1]     LOADK           1 -2    ; 255
        3       [1]     LOADK           2 -3    ; 1
        4       [1]     FORPREP         0 5     ; to 10
        5       [2]     GETTABUP        4 0 -4  ; _ENV "math"
        6       [2]     GETTABLE        4 4 -5  ; "random"
        7       [2]     LOADK           5 -1    ; 0
        8       [2]     LOADK           6 -2    ; 255
        9       [2]     CALL            4 3 2
        10      [1]     FORLOOP         0 -6    ; to 5
        11      [3]     RETURN          0 1

As you can see. The first piece has two extra instructions. One of them is inside the loop:

        11      [3]     MOVE            0 5

What this does is to move the result in the register 5 (which has the result of math.random, to the register 0 (which is where the variable t is). And that answers your question.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Ok, so for loops have their own scope, and accessing a local variable from the outer scope is slower, but is accessing a local variable from the outer scope slower than accessing a global variable too? – user6245072 May 19 '16 at 16:02
  • I mean, is it viable, in the code above, to declare `local rand = math random` outside the loop, and then call `rand` inside the loop? – user6245072 May 19 '16 at 16:05
  • @user6245072 The answer is yes. If the loop is long, assigning the function to a local variable outside the loop has a better performance. Chapter 2 of [*Lua Programming Gems*](http://www.lua.org/gems/) talks about this in depth. – Yu Hao May 19 '16 at 16:09
  • Never noticed that article. Cool. – user6245072 May 19 '16 at 16:22
  • @user6245072 Yes. In general, any time you indent in Lua is considered its own scope. That includes functions, do blocks, while/repeat/for loops – DavisDude May 19 '16 at 18:22
  • 1
    @DavisDude Yes, or more formally, everywhere "block" Is referenced in [The Complete Syntax of Lua](https://www.Lua.org/manual/5.3/manual.html#9) – Tom Blodget May 20 '16 at 13:04