Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua variable scoping with setfenv

Tags:

scope

sandbox

lua

I'm trying to use raw Lua files for configuration purposes, but don't want the config files polluting the global namespace.

The problem I'm running into is that dofile always seems to execute in the real global environment, so external files just throw all their declarations into _G.

Here's an example main file, with comments indicating my wishful thinking.

function myFunc()
    print("In the sandbox:")
    print("Should be 1:", a)  -- falls back to _G for lookup
    a = 2  -- instantiating new global for sandbox
    print("Should be 2:", a)  -- from sandbox
    print("Should still be 1:", _G.a)  -- from host environment

    dofile("loading.lua")  -- here's where things go wrong

    print "\nBack in the sandbox:"
    print("Should be 3:", a)  -- changed by loadfile
    print("Should STILL be 1:", _G.a)  -- unchanged
end

a = 1
local newgt = {} -- new environment
setmetatable(newgt, {__index = _G})
setfenv(myFunc, newgt)
myFunc()

print("\nOutside of the sandbox:")
print("Should be 1: ", a)  -- in theory, has never changed

And the file it's loading (loading.lua:

print ("\nLoading file...")

print("Should be 2: ", a) -- coming from the sandbox environment
a = 3
print("Should be 3: ", a) -- made a change to the environment

And finally the output I'm seeing:

In the sandbox:
Should be 1: 1
Should be 2: 2
Should still be 1: 1

Loading file...
Should be 2:  1
Should be 3:  3

Back in the sandbox:
Should be 3: 2
Should STILL be 1: 3

Outside of the sandbox:
Should be 1:  3
like image 693
SJML Avatar asked Jun 23 '10 02:06

SJML


People also ask

Is Lua lexically scoped?

The scoping that most programmers are used to is called lexical scoping. It's found in Lua and many other languages. Lexical scoping is the dominant choice for a reason: it's easy to reason about and understand just by looking at the code.

What does setfenv do?

Sets the environment to be used by the given function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling setfenv . setfenv returns the given function.

How do I use local variables in Lua?

You can access the local variables of any active function by calling getlocal , from the debug library. It has two parameters: the stack level of the function you are querying and a variable index. It returns two values: the name and the current value of that variable.

What is Lua scope?

If so, then you need to learn a very important programming concept known as scope. Scope impacts Lua's ability to "see" variables (as in the error above) as well your ability to manage where functions exist in relation to other functions and variables.


1 Answers

The problem you describe is also discussed on this page Dofile Namespace Proposal. The solution seemed to be the following replacement for dofile:

function myapp.import(name)
  local f,e = loadfile(name)
  if not f then error(e, 2) end
  setfenv(f, getfenv(2))
  return f()
end

See also: Sand Boxes

like image 196
gwell Avatar answered Oct 24 '22 01:10

gwell