Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
14

What are the Differences between "Local Function" and "Function"? [closed]

Asked by
woodengop 1134 Moderation Voter
9 years ago

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.

0
I guess that local functions are not stored in the server while normal functions are. I'm not so sure though fahmisack123 385 — 9y
0
You go to the wiki to find out, and then you script it. yoshiegg6 176 — 9y
5
yoshi, I just said that the ROBLOX Wiki did not provide an answer. woodengop 1134 — 9y

Locked by woodengop and adark

This question has been locked to preserve its current state and prevent spam and unwanted comments and answers.

Why was this question closed?

3 answers

Log in to vote
2
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago

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
4
To be honest, I didn't know about the out-of-order execution thing myself. adark 5487 — 9y
Ad
Log in to vote
4
Answered by
adark 5487 Badge of Merit Moderation Voter Community Moderator
9 years ago

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
Log in to vote
-3
Answered by
vat21s 0
9 years ago

Local functions are more optimized, and should be used where possible.

0
Please have a Better description, I couldn't quite understand that. woodengop 1134 — 9y
0
Please view this article http://wiki.roblox.com/index.php?title=Performance, A locally referenced function is quicker and easier for Lua to access than a global scope one. vat21s 0 — 9y