As a new — or relatively new — Lua/Solar2D programmer, are you confused by console errors like this?
Runtime error /Users/yourname/Projects/AwesomeGame\menu.lua:4: attempt to index global 'button' (a nil value) stack traceback: [C]: in function 'error' ?: in function 'gotoScene' /Users/yourname/Projects/AwesomeGame\main.lua:16: in main chunk
If so, then you need to learn a very important programming concept known as scope. Scope impacts Lua’s ability to “see” variables
When you think of terms like “telescope” or “microscope,” you think of devices that help you see, and see things within a limit — for instance, very small things in a microscope. In programming terms, scope is used to define what parts of your code can “see” variables, objects, and functions that you have created. In Lua, there are two main scope controls: global and local.
Global variables/functions can be seen anywhere in your program. “Great, I’ll use global scope for everything!” you might say, but global objects can actually be quite bad! In fact, new programmers should avoid using global variables.
One reason why globals are dangerous is that — because they have no visibility limits — they can be expensive to use in regards to performance. In fact, if a global variable is accessed in a
Global variables/functions also have the inherent risk of being accidentally _W
in one Lua file and assign it a value of 320
, you may accidentally create another global variable _W
in another file, assign it a different value, and effectively “trash” the first declaration. This could obviously have unexpected consequences in the first file which expects _W
to have a value of 320
!
The global scope is discussed in more detail in the Goodbye Globals! tutorial, along with a convenient method to create/access
In Lua, the preferred scope is local which you control by using the local
declaration before you define a variable/function. For example:
local someVariable
local function someFunction() end
When you prefix a variable or function with local
when you first create it, it becomes available to that block of code and any “children” blocks contained within. This concept is highlighted by the following two examples:
local function addTwoNumbers( number1, number2 ) -- Create variable "sum" local only to this "addTwoNumbers()" function local sum = number1 + number2 print( sum ) -- This works! end print( sum ) -- This does NOT work (prints "nil" meaning it's unknown to Lua)
In this case, the function addTwoNumbers()
defines a new block of code. Inside this block, we create a new variable named sum
. This variable has the local
keyword, meaning it’s only visible to the function addTwoNumbers()
— no other code in this module or overall project will be able to “see” the sum
variable. Thus, when the function ends, there is no longer a variable known as sum
and nil
will be printed to the console.
local function addTwoNumbers( number1, number2 ) local sum = number1 + number2 if sum < 10 then print( sum .. " is less than 10" ) local secondSum = sum + 10 end print( secondSum ) -- This does NOT work (prints "nil" meaning it's unknown to Lua) end
Like the first example, sum
is local to addTwoNumbers()
. That lets us add two numbers, and it’s also visible inside the block started by if sum < 10 then
if-then
secondSum
) is created, and that variable becomes local only to the if-then
secondSum
outside of the if-then
nil
because secondSum
doesn’t exist at that point in execution.
Consider a block of code like this:
local i = 999 for i = 1, 10 do print( i ) -- prints 1, 2, 3, .. 10 end print( i ) -- prints 999
Here, a local variable i
is set to 999
on line 1. In addition, a loop index variable of i
(line 3) is used, but this i
is local only to the for
loop. As the loop executes, its value represents the values 1
-10
print( i )
i
will forget its final value from the loop and return to its previous definition (usually nil
). Following that, the local variable i
which was declared before the for
loop is printed to the console (print( i )
on line 7999
. This is because for loops — just like functions — are blocks and they adhere to the same scope rules associated with blocks.
Hopefully, this tutorial has illustrated that scope, as an overall concept, is relatively straightforward. When you use the keyword local
, the variable can only be accessed at that block level or within any child blocks. With that in mind, if your variables or functions need to be seen at a wider level, simply move them above/outside the block or define them near the top of the module.