Lua: Scoping

From Mario Fan Games Galaxy Wiki
Revision as of 21:00, 15 December 2009 by Xgoff (talk | contribs) (Created page with '{{Lua}} '''Scope''' is a variable's "visibility" to other parts of the program. In Lua, variables can be globally or locally scoped; the latter by using <tt>local</tt> in the…')
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Lua
Lua.gif
Basics
Intermediate
Advanced
XLua
Add to this template
 Standardwikimessagebox.png This article assumes the use of Lua 5.1.

Information may not be accurate or may need revision if you are using a different version.

Scope is a variable's "visibility" to other parts of the program. In Lua, variables can be globally or locally scoped; the latter by using local in the variable declaration. Global variables can be accessed by anything and at any point, but local variables are only accessible by code within the same scoping block.

Lua uses static, or lexical, scoping. A simple way of thinking about it is that a variable with a given name will be accessible until a "more" local variable sharing the same name is declared:

a = 1 -- global 'a'
print(a) --> 1

do -- begin scope level 1
    local a = 10
    print(a) --> 10

    do -- begin scope level 2
        local a = 100
        print(a) --> 100
    end -- end scope level 2

    print(a) --> 10
end -- end scope level 1

print(a) --> 1

An important thing to remember is that a variable declared with local does not enter scope until after the declaration. This allows constructs like:

local a = a

Where the a on the right is the a currently in scope; the a on the left will be assigned this value and then will be in scope.

Restricting Variable Access

For instance, the following is a much better way of redefining the built-in functions. We want require to block the usage of certain modules:

do -- opens a new scope
    local oldrequire = require
    local blocked = {badmodule = true, takeovermycomputer = true}
    function require(module)
        if not blocked[module] then -- this could be more robust, but as an example...
            oldrequire(module)
        else
            error("not allowed to use module '" .. module .. "'")
        end
    end
end

print(type(require), type(oldrequire), type(blocked)) --> "function", "nil", "nil"

When we enclose code in a do...end block, any local variables declared in that block are only accessible within that block. A naive way of redefining require would leave oldrequire in the global namespace, where a user would easily be able to find it by simply dumping _G. However, by enclosing it in this manner, only our new require can see it. Similarly, blocked is hidden from the end user in the same way. Because we did not declare require as local, it can be seen outside the do...end block, as it is global.

Upvalues

In the above example, oldrequire and blocked are upvalues to require. Upvalues are local variables that are accessible to a function within the same scope. Generally, upvalues are seen in iterator functions, as they are often used to keep the state; when bound to a closure, their value remains between calls of that closure. They are similar to C static local variables in this respect. Old versions of Lua prior to 5.0 required decent knowledge of upvalues as they had to be referenced by prepending a '%' to the variable name.