I don't completely understand setfenv

Is there a way I can use setfenv while keeping the original environment at the same time?

Sort of.

You can’t have both at once, but you can pass through failed indexes in your new environment to your old environment. You can do this using the __index metamethod, which handles what happens when you try to get a value from a table the doesn’t exist. Here’s an example:

local function passthroughEnv(func, newEnv)
	local oldEnv = getfenv(func)
	setmetatable(newEnv, {
		__index = function(self, index)
			return oldEnv[index]
		end
	})
	return setfenv(func, newEnv)
end

Any value already in newEnv is returned, but if it doesn’t exist in newEnv then __index is called, which will return the value from oldEnv.

Any new values you set will go into newEnv. You can control this with the __newindex metamethod if you need to.


Lua lets you do a little shortcut with the __index metamethod: you can set it directly to a table and it will just use that table’s members. Makes things lots easier!

Knowing this, we can write the following:

local function passthroughEnv(func, newEnv)
	local oldEnv = getfenv(func)
	setmetatable(newEnv, {
		__index = oldEnv
	})
	return setfenv(func, newEnv)
end

You can do other stuff with metatables. You should really learn them if you haven’t already!

Even though I’ve answered your question, I really wouldn’t advise messing with function environments unless it’s just for fun. It makes code harder to understand and maintain, and it messes up Roblox’s built-in helper checks.

11 Likes

I wrote my own script builder back when those were popular. Used metatables and setfenv to sandbox scripts made by the user.

I can’t really think of another use for setfenv besides script sandboxing, in any case. It is pretty interesting from a theoretical point of view, though.

Thank you so much. I just am making an admin system and wanted to add a built in set of stuff for each command without having to pass it through a function.

1 Like