Reputation: 209
This is a dummy variant of a setup I'm running. The Launcher function does not seem to see the GetLevel. At least the first print is seen but the second isn't. So the function never starts. Is that because the code comes after the place it is launched it in the code, and at the point Launcher executes it doesn't exist yet? When I remove the local tag it works. So global functions can be "seen" from anywhere in the script, but local ones only from later in the code? I'm trying to find out which functions I can make local, as they are all currently global. Is there even a benefit to this - is there a difference between a function that's local to the entire script and one that's not local?
local UseLevel = true
local Limit = 0
local function Launcher()
print("trying to launch GetLevel now")
GetLevel()
end
local function GetLevel()
print("GetLevel was launched")
if UseLevel then
Limit = 4
else
Limit = 5
end
end
Upvotes: 2
Views: 876
Reputation: 11171
Is there even a benefit to this - is there a difference between a function that's local to the entire script and one that's not local?
The benefit of using locals is twofold:
First, locals are usually faster, as they simply use registers in Lua's virtual machine whereas globals are entries in the global table (which is effectively a hash map). Calling a global function requires first indexing the hash map.
Second, locals help improve code quality, as they are only visible in their local scope (say, a file, or even within an if-branch, a loop or the like). Putting everything in the global scope is known as "global pollution" and frowned upon. It also slows down global access as it bloats the global table. Note that Lua allows changing the environment using _ENV
(or setfenv
in older versions), so you can sometimes save yourself both the local keyword and forward declarations by doing so without polluting the global environment. Usually you shouldn't change environments though.
Globals are often used to expose interfaces as pointed out by Nicol Bolas. You can alternatively use return my_api_table
at the end of your files for this; the API table can then be "imported" using local my_api_table = require(relative_path)
.
Is that because the code comes after the place it is launched it in the code, and at the point Launcher executes it doesn't exist yet?
Yes. You can fix this using a "forward local declaration" of GetLevel
:
local UseLevel = true
local Limit = 0
local GetLevel -- "forward declaration" for Launcher
local function Launcher()
print("trying to launch GetLevel now")
GetLevel()
end
-- This is the same as GetLevel = function() ... end and thus does not set a global variable
-- but instead assigns to the previously declared local variable GetLevel
function GetLevel()
print("GetLevel was launched")
if UseLevel then
Limit = 4
else
Limit = 5
end
end
Simply putting the Launcher
function below GetLevel
also works:
local UseLevel = true
local Limit = 0
local function GetLevel()
print("GetLevel was launched")
if UseLevel then
Limit = 4
else
Limit = 5
end
end
local function Launcher()
print("trying to launch GetLevel now")
GetLevel()
end
Upvotes: 4
Reputation: 28950
The other guys already told you something about locals and globals in general. Let's take a look at your code and understand why this is not working.
local UseLevel = true
local Limit = 0
local function Launcher()
print("trying to launch GetLevel now")
GetLevel()
end
Above you defined three local variables. A boolean, a number and a function value. Launcher
calls GetLevel
which, assuming this is the only code you execute, is a global nil value. Because until that line you neither defined a local nor a global variable with that name. If you have never assigend a value to a variable, it is a nil value and if you have never declared that variable local it is a global nil value.
Then you define a local function named GetLevel
. This is a new local variable. It is not the same GetLevel
you used when you defined Launcher
. Because that was a global variable.
local function GetLevel()
print("GetLevel was launched")
if UseLevel then
Limit = 4
else
Limit = 5
end
end
So when you later call Launcher
it will still use the global nil value. Not the local which it doesn't know anything about.
The only way to make this work is to assign a function value to the very same variable that is being used in your Launcher
definition. The scope does not matter as long it is the same reference. The only way to make this work with locals is to declare that local reference befor you define Launcher
.
it does not matter if you define GetValue
befor or after Launcher
as long as it has been defined when you call Launcher
.
Upvotes: 3
Reputation: 473252
So global functions can be "seen" from anywhere in the script, but local ones only from later in the code?
Yes, "global" means global.
You make something local if you don't want it to be visible outside of the script. A script should not expose something to the outside world unless the outside world needs to see it. Expose only interfaces, things the external code will actually talk to.
Upvotes: 2