What is the difference between these two small codes?

Type 1:

local var = nil

function foo()
print(var)
end

var = 10
foo()

Type 2:

function foo()
print(var)
end

var = 10
foo()

Is there any advantage of doing the type 1?
I’ve been doing it all the time and I can’t figure out why…

Using local variables means you’re not polluting the global scope, and is generally better code practice. Especially when you can confine the scope of the local tighter than “the entire file”, for example:

function foo()
    local result
    for i = 1, 10 do
        if math.random(1, 10) == 0 then
            result = true
            break
        end
    end
    print(result)
end

If you don’t declare a local here, it means that anywhere else in the file that you use a variable with the same name will interfere. It also means that the value won’t be initialized to nil when the function is called.

In cases where your local is in the top level scope, it’s at least consistent with using local elsewhere in the file.

One important thing to note is when you’re working with Lua outside of Roblox, assigning to variables that haven’t been declared with local puts them into _G and makes them shared with other modules such as those that you require().

Most Lua linter tools consider non-local variables bad practice because of this, including our own script analyzer. It makes local reasoning close to impossible because the variable may have been set from literally anywhere in the file, and it makes it difficult to impossible to tell whether a variable has actually been defined before using it. This is especially relevant because it makes it difficult to tell if e.g. instance is a typo of Instance or simply a variable you’ve declared.

2 Likes

I recently had to send someone this example and he said it was very useful so here ya go :smile:

local a = 1
local b = 2

local function test()
	local c = 3
	local b = 4
	d = 4
	print(a, b, c, d) --> 1 4 3 4
end

test()

print(a, b, c, d) --> 1 2 nil 4
2 Likes

So basicallly in roblox, defining local variables at the top of your script is simply to make your code look clean?
It has no actual effect in terms of safety from hackers etc (Hai all hackers reading my posts :wave::smile:)?

1 Like

Well, it’s more than just aesthetics. Local variables have faster access than global variables. Also, local and global functions behave slightly differently. Sometimes you will have to forward declare local functions in order for your code to work properly. This caused me a few headaches many years back.

As for security, if nothing else it’s probably safer to use local variables, since they are stored on the stack and not in the function environment. However I’m not an expert in this area, so I am unsure to what extent this would improve security.

1 Like

You’re saying type 1 is stored on stack but type 2 is not?

Aren’t they in same scope being they are in topscope of the script?

‘Global’ variables are accessible by getfenv and setfenv, the function environment. Local variables are not. getfenv and setfenv in a nutshell allow you to treat global variables like they were stored in a typical table. Actually, getfenv returns such a table. I digress.

They are in the same scope, yes, but they are handled much differently C-side. They aren’t as similar as they look.

Edit: Just for the sake of example, here is a case where it will function differently.
test = function()
    print(test)
end

If you run the above, it will print the found function.
However, this next code will print nil:

local test = function()
    print(test)
end

If you do this little trick called forward declaring, you can work around the issue:

local test
test = function()
    print(test)
end

Note that this is still a local variable even though the actual declaration did not have the local prefix.
According to learncpp’s website,

A forward declaration tells the compiler that an identifier exists before it is actually defined.

For basically every case (Barring usage of the function environment) it is a good policy to stick to local variables.

  • They are cleaner - they don’t leak into parent scopes
  • They are a better practice - nearly every other programming language treats all variables like Lua treats locals.
  • They are noticeably faster and it is an easy way to get a moderate performance boost for tight loops.
4 Likes

I thought Roblox localizes variables in the global scope by default now?

Nope. Run this code on ROBLOX:

d = 0
print(getfenv(0).d) --> 0
local e = 0
print(getfenv(0).e) --> nil

I could of sworn I think zeuxcg talked somewhere about automatic localization