That is not flexibility. You should know what your functions do beforehand before you call them.
You did not understand. I know what my functions does.
But when the function is declared as Local, I am obliged to always place it at the top of the code, in the first few lines.
When the function is not local, I have the flexibility to declare it more in any part of the code.
Example:
function func2()
func1()
end
function func1()
print('OK')
end
func2() -- works
function func2()
func1()
end
local function func1()
print('OK')
end
func2() -- don't work
To keep func1()
as local
I have to move it before func2()
:
local function func1()
print('OK')
end
local function func2()
func1()
end
func2() -- works
Now imagine that having to be done constantly in a large code, I always have to rearrange the functions within the code, just because they are declared as local
…
Which is a good thing! That means everything is in order and you know what it does beforehand.
For your second example I had to look down to see what it did. That is not good.
Now, in one thing you are right: local variables are faster. And I say this because I made a benchmark using this code.
From the results I tested, I can assert:
local variables are processed 3 to 4 times FASTER than global variables
I believe local variables are always better than globals, but you are right that this restraint on a function’s location is oftentimes terrible for code organization.
Say you have 4 functions, each implemented in the last:
function findInTable() ...
function indexTable() ...
function validateIndex() ...
function decodeIndex() ...
It’s more of a pain to scroll down to find the main functions at the bottom than it is to simply glance at them right at the top. i.e, you find the findInTable
function at the bottom, but a new reader (like future you from 2 years in the future) would be confused as to why s/he is finding all these technical functions like decodeIndex
surfacing up top. Unless, you still have a trained instinct to scroll straight down to the bottom, unlike me.
The usual answer in Lua is “tough,” but you can use tables to stay local while receiving the benefits of globals at the same time:
local TableLib = {}
function TableLib.Find() ...
function TableLib._index() ...
function TableLib._validateIndex() ...
function TableLib._decodeIndex() ...
Accessing these functions are probably just as fast as accessing a global, if not slower, but I don’t really know.
Also, having to keep reading down to find the main functions and know what they do is time-consuming and uses up the mental power you need to move on to the next feature or fix the next bug. It is much more professional (in my opinion) to be able to assume what your code does and trust that it works through clear and concise function/parameter names and without having to understand lower-level implementations. If you need more information, you keep reading down, and if you only need a gist, it’s right there.
When your declaring variables or functions its is always bet to have them at the top of the script, current control statement, loop or function anyways, so I don’t see that as a disadvantage.
You are all insisting that having a function declared at the beginning of the program is easier for understanding a code and that “scroll down” the code to find the function is worst.
This may even be true for small code.
But that makes no difference in a code with THOUSANDS OF LINES, with HUNDREDS OF FUNCTIONS. In this case, you will not “scroll down”, you will always have to search for the function via Ctrl+F.
Hence, it makes no difference whether the function is above or below in the program.
But it is rather a disadvantage when you try to run the code and Studio warns you that the function does not exist just because you declared it as local and then you have to move it through the code until you find an ideal line for the function to be found by the compiler.
Then you discover that there were other functions that depended on this function that you moved, so you have to rearrange these other functions as well, and so on. A nightmare!
Store functions in modules so you can just require them at the top of your script and call them accordingly. Fortunately this forces you to have your functions modular which means no global variables.
I believe it’s just personal preference. I always declare my functions as local since if I needed a global function I would prefer to use a Module Script and require that. But as @rogeriodec_games has mentioned in their previous reply their can me drawbacks for some people.
All I can say is local functions can guide people into cleaner code. Since you will always have your functions above your main loop or event logic.
Local functions can only be used in one script, while normal functions (Global Functions) can be used from any script in the game.
Within the one defined as local function, foo (its name) can be accessed as an upvalue for recursion, while in the local foo = definition , it can not.
If you’re just planning to use it in one script, go for local functions.
Really? I’m pretty sure a global scope is only ‘global’ through that script only.
Render()--<Error
Renderv1()--<Will work
local function Render()
print("Rendering");
end;
--
function Renderv1()
print("Rendering");
end;
For global variables/functions across scripts, you’ll need to use _G
Yeah, it’s only ‘global’ insofar as it’s accessible from that specific script, which is why I find it kind of pointless to argue about imo. Functionally they’re nearly identical, and while there may be some performance advantages in using local functions, I would guess that for 90% of use cases it won’t be big enough to make a difference. For most use cases, at least with Roblox, it’s gonna come down to a preference and how you’re organizing your code.
Probably meant any block in the script, unless you mean defining functions globally as in literally globally in a shared environment.
Defining a function through syntactic sugar:
local function foo() end
-- is the same as doing
local foo; foo = function() end
and defining functions locally makes them faster to access since the local is added to the stack.
That is another issue your touching on, if your code spans thousands of lines, your more than likely doing too many things in that single script/module. imo no source file should be more than 1000- 1500 lines long.
Why? What’s the difference between 1,500 and 15,000 lines? From 500 lines long, in my opinion, it is already difficult to move through the code without using bookmarks, collapsing, Ctr+F, and other tools (that’s why I use Sublime Text 3 and not Studio’s native editor).
So, no matter if you have 1,500 or 15,000 lines, the job will be the same.
Yeah of-course it will do the same thing but it will make your code terrible to maintain.
Why? A single script’s strategy is highly recommended by many developers. In this case, I’ll have only 3 scripts: a LocalScript, a ServerScript and a ModuleScript.
I think it is much easier to maintain the code in this way than to distribute it unnecessarily in several scripts, which, on the contrary, makes maintenance more difficult.
Is there any advantage to declaring a function as
local
?
Yes. They are faster to access, and you avoid polluting the global* namespace. Here is some info about the global environment from PIL.
For simple programs, honestly, it probably doesn’t matter what you do. As your programs get more complex, though, you will start to realize the benefits of well-defined scope.
Because so far I’ve only seen disadvantages : without
local
, the function can be located anywhere in the code and when declaredlocal
, the function must always be above the line that calls it.
This is false. The following fails:
printHello() -- attempt to call global 'printHello' (a nil value)
function printHello()
print("Hello")
end
You may be referring to something like this:
workspace.Part.Touched:Connect(function()
printHello()
end)
function printHello()
print("Hello")
end
This works because when you declare something without local
, you are actually putting it in a table that is shared for the entire script*. The printHello()
call triggers a lookup in that global* table.
However, that’s not a unique thing to globals, it’s more of a side-effect of the way lua is evaluated (at runtime). This works too, but makes printHello a local function:
local printHello
workspace.Part.Touched:Connect(function()
printHello()
end)
function printHello() -- same as printHello = function()
print("Hello")
end
You still need the forward declaration at the top, since you’re not storing the variable in the global* table, but you can put the definition wherever you want.
*: in non-roblox Lua, every non-local variable is put in _G and shared among all modules in the program – not true for ROBLOX. In ROBLOX Lua, each script has its own “global” table that other scripts cannot access.
Just to confirm that functions declared as Local
are REALLY faster than global functions, I created a benchmark below:
local elements = 100000000
local keyToFind = "k" .. elements
function GlobalFunction()
return true
end
local function LocalFunction()
return true
end
-- benchmark
local time = tick()
for i = 1, elements do
GlobalFunction()
end
local timeG = tick() - time
print("seconds to run a Global function:\t", timeG)
local time = tick()
for i = 1, elements do
LocalFunction()
end
local timeL = tick() - time
print("seconds to run a Local function:\t", timeL)
print()
print("Local functions were" .. math.round((timeG / timeL - 1) * 100) .. "% faster than Global functions")
Result:
seconds to run a Global function: 3.0561254024505615
seconds to run a Local function: 2.423032283782959
Local functions were 26% faster than Global functions
Running 10 million iterations, it can be seen that calls to local functions are almost 30% faster than calls to global functions.
Thanks for the benchmark testing. For anybody scrolling upon this from 2024, I tried the same benchmark and results have significantly improved.
Blockquote
seconds to run a Global function: 1.7780334949493408
seconds to run a Local function: 1.645150899887085
Local functions were 8% faster than Global functions
So depending on the script, in general it shouldn’t really matter which one you use, which means you can have the ease of access of using global functions and being able to declare them anywhere.
Unless you still want that 8% boost