Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

What are the Differences between "Local Function" and "Function"?

I know from all my studying that a FunctionFires an Event, But what is the Difference between: Local Function, and a Regular Function?

NOTE: The ROBLOX Wiki did NOT Provide an Answer for this.

3 comments

0

I guess that local functions are not stored in the server while normal functions are. I'm not so sure though

0

You go to the wiki to find out, and then you script it.

5

yoshi, I just said that the ROBLOX Wiki did not provide an answer.

3 answers

✓ Accepted answer

adark missed the biggest practical different between local functions and not.

Global variables can be used lexically (in order in source) before they were declared. For instance,

function blah()
	print( a ) -- where a is a global (not local) variable
end

a = 5
blah()
-- 5

local variables are only usable after them (lexically -- in source order):

local a = 5 
blah()
-- nil

The same applies to local functions -- they can only be used after they are declared, thus the following is invalid:

function blah()
	print( a() )
end

local function a()
	return 5
end

blah() -- a() will cause "attempt to call a nil value"

In addition, it lets you hide functions entirely:

do
	local function blah(x)
		return x + math.random()
	end
	
	function save(x)
		return blah(x)
	end
end

print(save(5)) -- 5.432426812304
print(blah(5)) -- attempt to call a nil value

According to Programming in Lua, the following two are equivalent:

local function name()
	--body
end

local name; name = function()
	-- body
end

1 comment

4

To be honest, I didn't know about the out-of-order execution thing myself.

There is no difference between 'local' functions and 'normal' functions, actually.

First, a bit of clarification: Functions do not fire events, they listen to them. The ROBLOX engine itself fires them, passing in relevant information as arguments. Also, Function is invalid, as Lua is case-sensitive.

What's going on is a shortcut of Lua:

function Name(params)
	--end
end

--Is the EXACT SAME as:

Name = function(params)
	--end
end

Functions are first-class values in Lua, meaning that you can treat them as any other kind of variable. If you are familiar with C, Lua functions are more accurately function pointers.

This is why you'll see code like this:

loadstring(str)() --Where 'str' is a string of valid Lua code

The first set of parentheses calls loadstring, which returns a Lua function. The second set of parentheses calls that function.


As you probably know, the local keyword in Lua indicates the scope of a variable. If not, let me explain:

var1 = true --Global variable. In many implementations, this would be shared across 'Scripts'. Not in ROBLOX, however.

local var2 = false --Local variable, to the script. Functionally identical to the above, since the 'scope' is the entire script. Is slightly faster to access.

do
	var3 = "Red Fish" --Global variable. Even though it is declared inside of a code block, it is accessible outside of it.

	local var4 = "Blue fish" --Local variable. *Not* accessible outside of this code block.

	print(var1) --> true
	print(var2) --> false
	--Variables are always available in "child" blocks, like this one.
end

print(var3) --> Red Fish
print(var4) --> nil
--var4 goes out of scope here, so we cannot access it.

do
	local var2 = "Yellow Fish"
	local var3 = "Pink Fish!!!"
	--Local variables "override" higher-scoped variables.

	print(var2) --> Yellow Fish
	print(var3) --> Pink Fish!!!
end

print(var2) --> false
print(var3) --> Red Fish
--Local overrides go out of scope, and the original values are `restored`. 

When you make a function local, the same rules apply. Using top-level local variables in place of globals gives a considerable performance increase after a while, so that's why it's common to see them.


One last word on functions, and Tables as well:

Unlike other variables types, functions and Tables are, effectively, pointers. This is why you get something like this when you try to print them. When you pass a Table or function around as an argument to some function call, you are actually passing a reference to the Table/function. Any other variable type is copied into a function's 'upvalues', which are the parameters:

local function RunThis(tableParam, functionParam, otherParam)
	tableParam[27] = true
	otherParam = otherParam .. "YOLOSWAGGY"

	print(tableParam)
	print(functionParam)
	print(otherParam)
end

local str = "String"
local tab = {"Test1", "Test3"}

print(str) --> String
print(tab[27]) --> nil
print(tab) --> table: XXXXXXXA
print(RunThis) --> function: XXXXXXXB

RunThis(tab, RunThis, str) --> table: XXXXXXXA, function: XXXXXXXB, StringYOLOSWAGGY
-- I use 'RunThis' twice here. The first access is called as a function, indicated by the ()'s, but the second is merely referenced as a Variable.

print(str) --> String
print(tab[27]) --> true
print(tab) --> table: XXXXXXXA
print(RunThis) --> function: XXXXXXXB

tab and RunThis are pointers, to a Table and a function, respectively. RunThis() calls the function at the end of the pointer.

Notice, modifying the str upvalue passed into the RunThis call does not modify the external str variable. Modifying the Table's members, however, does modify the external Table. It is not possible (AFAIK) to modify the external function using just its upvalue.

A further note on upvalues: they act as local variables, following the rules above, so:

local tab = {}
local tab2 = {}

function RunThis(tab, X)
	tab = {X = 25, Y = 17}

	X.X = 26
	X.Y = 17
	X = {}
end

RunThis(tab, tab2)

print(tab.X) --> nil
print(tab.Y) --> nil
--The `tab` upvalue in the function *overrides* the higher-scoped `tab` declaration on line 1.

print(tab2.X) --> 26
print(tab2.Y) --> 17
--The same thing here. Even though we set X to an empty Table at the end of the function, that simply overrode the upvalue.

And, finally, reusing local variables:

In the above code, you'll notice that I did not write local X = {}. This is because X is already local. Since it was declared in the function definition as an upvalue (remember, parameters are upvalues), rewriting it in the 'global' scope simply reuses whatever scope the variable already had.

This is because variables in Lua do not have a specified Type. That is,

local x = true
x = "false"
x = 261

Is all valid Lua. In a language like C, that kind of code would produce a compile error, as x is either a Boolean or a String or an Integer, and definitely not all three at once.

All three of those x declarations are local, because the initial declaration is. When a higher-scoped variable is overridden, the most recent scope is used:

local x = 27

function RunThis()
	x = 45 --Same var as on line 1. If this code were all wrapped in a code block, this would not be accessible outside of it.

	local x = 18 --New scope, to this function.

	x = "BOOLEAN" --Same scope as the line above, *not* the same as Line 1.	
end

RunThis()

If you've been paying attention thus far, you'll realize that you can declare functions inside of code blocks:

function makeFunction(str)
	local function func()
		print("yolo" .. str)
	end

	return func
end

makeFunction("swag")() --> yoloswag

And as members of Tables:

local tab = {}

tab.Func = function()
	--code
end

--Or:

function tab.Func2()
	--code
end

This second case is how you can make methods as opposed to functions:

tab = {Applesauce = true}

function tab.func(t)
	print(t.Applesauce)
end

function tab:func2(appl) --Note the `:` here.
	self.Applesauce = appl --"Method declaration" gives you a `self` parameter.
end
--This function is identical to:
function tab.func2(self, appl)
	self.Applesauce = appl
end

--You can call these as either functions *or* methods:

tab.func1(tab) --> true
tab.func2(tab, "Hooligans!") --Although we edit the Table passed to the function, and not `tab`, this works because only the Table *reference* is sent, not a copy of the Table.

tab:func1() --> "Hooligans!"
tab:func2(true)

--And, finally, you can actually use *other* tables in these functions calls:

local tab2 = {}

tab.func2(tab2, "Peanuts")
tab.func1(tab2) --> Peanuts

This discussion is preserved as it was. New answers, comments, and votes are closed.