MiniScript's locals, outer, and globals
Just recently on the MiniScript Discord, someone was asking for support with a function of his that was supposed to modify a variable external to his function -- except it wasn't working. Given how this could be a gotcha, I figured it would be a topic worth exploring here in greater detail. Let's say we have a game where the player has an inventory that can only hold one item. We want to have a function that sets the inventory item, which we'll store in a global. inventory = "empty" // default item setInventory = function(item) inventory = item end function Let's test the code: print inventory // "empty" setInventory "key" print inventory // "empty" ???? What is going wrong? Why is the inventory still empty? With code this simple, it should be pretty clear that our function is not setting the global inventory variable. We might ask for some help, and someone will tell us to change inventory = item to globals.inventory = item. Perfect! It works. But why? The locals and globals maps MiniScript has two particular maps worth knowing about right away: locals globals When you set a variable by doing, let's say, x = 5, it's the equivalent of doing locals.x = 5. This locals map is built into MiniScript's inner workings. globals is the map that contains all of the variables that are set at global scope. When your script begins to run, if you begin executing code without putting it inside any function, and if it's not an imported module, then the globals reference points to the same map as the locals reference. locals.x = 5 globals.x = 6 print locals.x // prints 6 If this script is run on its own and outside of any function, then locals.x and globals.x are indeed the same variable, because locals and globals are the same map. This is why you can explicitly test if locals == globals in order to run different code, allowing for unit tests in your modules, tests that can be executed on their own but ignored when imported. Outer There is a third map available called outer. This one is a bit more niche. It is used for inner functions to access variables local to its outer function. When your script first starts (again assuming it's being executed on its own and outside of any function) locals == globals and locals == outer and outer == globals will all resolve to true. Easy enough. This is why you don't usually need to be concerned with outer, because often enough, even from within a function, outer == globals will resolve to true. Reading vs Writing Let's say you are trying to print a variable named total. How does MiniScript look up the variable? MiniScript first searches inside the locals map. If it doesn't find it, it tries to find it inside the outer map. If it doesn't find it there, then it tries globals. Finally, it raises a runtime error if it hasn't been found. This is different from writing, in which case, MiniScript always assumes locals is where you want to write your variables unless you explicitly specify a different map. This is why we can print the value of globals.inventory without explicitly mentioning globals, but we can't write to it without the explicit reference. Therefore, for reading, you do NOT need to use explicit references to locals, outer, or globals -- unless you are purposely trying to bypass shadowing. (Although if you are trying to do that, perhaps consider if shadowing is really a good idea for you in the first place.) For writing, you must explicitly use a reference to the correct map, if you do NOT wish to use locals. Summary The order of variable lookup for reading is locals, then outer, and then globals. Variables are written to locals by default. If you want to write to a variable outside of locals, you must specify the map explicitly, whether outer or globals.

Just recently on the MiniScript Discord, someone was asking for support with a function of his that was supposed to modify a variable external to his function -- except it wasn't working. Given how this could be a gotcha, I figured it would be a topic worth exploring here in greater detail.
Let's say we have a game where the player has an inventory that can only hold one item. We want to have a function that sets the inventory item, which we'll store in a global.
inventory = "empty" // default item
setInventory = function(item)
inventory = item
end function
Let's test the code:
print inventory // "empty"
setInventory "key"
print inventory // "empty" ????
What is going wrong? Why is the inventory still empty?
With code this simple, it should be pretty clear that our function is not setting the global inventory
variable. We might ask for some help, and someone will tell us to change inventory = item
to globals.inventory = item
.
Perfect! It works.
But why?
The locals and globals maps
MiniScript has two particular maps worth knowing about right away:
- locals
- globals
When you set a variable by doing, let's say, x = 5
, it's the equivalent of doing locals.x = 5
. This locals
map is built into MiniScript's inner workings.
globals
is the map that contains all of the variables that are set at global scope. When your script begins to run, if you begin executing code without putting it inside any function, and if it's not an imported module, then the globals
reference points to the same map as the locals
reference.
locals.x = 5
globals.x = 6
print locals.x // prints 6
If this script is run on its own and outside of any function, then locals.x
and globals.x
are indeed the same variable, because locals
and globals
are the same map. This is why you can explicitly test if locals == globals
in order to run different code, allowing for unit tests in your modules, tests that can be executed on their own but ignored when imported.
Outer
There is a third map available called outer
. This one is a bit more niche. It is used for inner functions to access variables local to its outer function.
When your script first starts (again assuming it's being executed on its own and outside of any function) locals == globals
and locals == outer
and outer == globals
will all resolve to true. Easy enough. This is why you don't usually need to be concerned with outer
, because often enough, even from within a function, outer == globals
will resolve to true.
Reading vs Writing
Let's say you are trying to print a variable named total
. How does MiniScript look up the variable?
MiniScript first searches inside the locals
map. If it doesn't find it, it tries to find it inside the outer
map. If it doesn't find it there, then it tries globals
. Finally, it raises a runtime error if it hasn't been found.
This is different from writing, in which case, MiniScript always assumes locals
is where you want to write your variables unless you explicitly specify a different map. This is why we can print the value of globals.inventory
without explicitly mentioning globals
, but we can't write to it without the explicit reference.
Therefore, for reading, you do NOT need to use explicit references to locals
, outer
, or globals
-- unless you are purposely trying to bypass shadowing. (Although if you are trying to do that, perhaps consider if shadowing is really a good idea for you in the first place.) For writing, you must explicitly use a reference to the correct map, if you do NOT wish to use locals
.
Summary
- The order of variable lookup for reading is
locals
, thenouter
, and thenglobals
. - Variables are written to
locals
by default. - If you want to write to a variable outside of
locals
, you must specify the map explicitly, whetherouter
orglobals
.