Scope is a block of code in which variables are declared and accessible. Code blocks like for-loops, while-loops, repeat until-loops, functions, if-then statements, and do-end chunks all create a new variable scope. Variables created within a contained scope are discarded and “forgotten” (a.k.a. “garbage collected”) when the scope is exited.
Variables can be declared in two ways: locally (with the
local keyword), and globally. Global variables are always in scope: no matter where you declare them, they are always accessible. All variables default to the global scope unless they are explicitly placed in the local scope using the
Global variables are only global within the content of the associated script. In other words, a script is not able to access the global variables contained by another script. If you need the ability to do that, register your variables in the
_G table - a shared data construct accessible to all scripts.
Let’s take a look at some examples.
When myFunction was called, myVariable was set to 64. Since this variable is globally scoped, it could be accessed outside the function. This is why the output was “myVariable is 64”. Take a look at this example using the
local keyword to change the scope of a variable.
That was outputted because myVariable was confined to myFunction’s environment or its scope. Therefore, it was not able to access the value outside of that function.
do end block creates a new scope. This can be useful to create a new block of local variables, without overriding the non-local variables. If you have a long script with a lot of variables, this can be useful. Remember that you can also create local functions using this.
Notice here that the “Pear” variable isn’t changed to its “original” non-local value, because we didn’t use the local statement in the do block.
In the last example you may have noticed that I said “the variable was also accessible by descendant environments”. This concept is called lexical scoping.
if true then --level 1 local a = 82.5 if true then --level 2 local b = 64 end end
This is a simple example with two conditionals. If you recall, conditionals also have their own environment. Here is a snippet to prove this:
if true then --level 1 local a = 82.5 if true then --level 2 local b = 64 end print(b) --> nil end
Its nil because variable b was confined to the scope of the second conditional. Lexical scoping will allow one to do this:
if true then --level 1 local a = 82.5 if true then --level 2 print(a) --> 82.5 local b = 64 end end
Even though the second conditional has its own environment, because of lexical scoping,
a was inherited. Variables that are lexically scoped are called upvalues.
Using the “local” statement
You can also define a local variable in a scope without assigning any value to it, but making it possible to read that variable on the current “scope level”. You can do this by using the “local” keyword and then the variable name behind it. An example:
function whereIsHi(t) local foundAt for key, value in pairs(t) do if value == "Hi" then foundAt = key end end return foundAt end
This code would return nil if the table “t” does not have a table “Hi” in it, and otherwise will return the last index found which contains the “Hi” value.
local foundAt not used, then
foundAt would be globally scoped, making it accessible elsewhere, and making
whereIsHi overwrite any variables with the name
foundAt from outer scopes.