Jump to content




Lua Function Environments


  • You cannot reply to this topic
7 replies to this topic

#1 ElvishJerricco

  • Members
  • 803 posts

Posted 25 June 2013 - 02:52 PM

One of Lua's most powerful features is setting function environments. Environments are tables that hold the global values that a function references.

function a()
	c = 3
end
a()
print(c)

The function a sets the global variable c to 3. Also, the declaration of the a function sets the global a to that function. The result of this program is printing the number 3.

So what table is holding these a and c keys? That's known as the environment! For programs run from the shell, the environment is a shared one across all programs run by the shell. So if you set a global in one program, the environment holds onto it, and any other program can access it.

But how do we set our own environments? There's a nice little function called setfenv.

local function a()
	c = 4
end
local env = {}
setfenv(a, env)
a()
print(env.c)

a gets its environment set to env, so when c is defined globally, it is stored in env. So now we can keep track of the globals declared by a function. But this leaves us with a problem. Now a can't access global functions. This is easily solved with metatables

local function a()
	print("test")
end
local env = setmetatable({}, {__index=_G})
setfenv(a, env)
a()

And now we can get pretty clever with setting and getting variables. If we wanted to, we could create a setter/getter system that could be very useful.

local setters = {}
local _width
function setters.setWidth(w)
	-- We can not only set the local _width value, but also do some logic
	_width = w
	redrawScreen()
end

local env = setmetatable({}, {__index = getfenv(), __newindex=function(t,k,v)	-- FYI, getfenv has various functions
										-- one of which is to get the current environment
	local setter = setters["set" .. k:sub(1,1):upper .. k:sub(2)]
	if type(setter) == "function" then
		setter(v)
	end
end})

local function f()
	width = 5 -- now setting this width key automatically calls a redraw routine!
end
setfenv(f, env)
f()

In writing that, I almost made a mistake that should be noted. I accidentally called the local _width variable width. This would have been a problem. f() would be referencing a local variable, instead of setting a global, and the environment __newindex metamethod never would have been called.

So hopefully this shed some light on the idea of globals, that seems so mysterious to so many people. Happy coding!

#2 Engineer

  • Members
  • 1,378 posts
  • LocationThe Netherlands

Posted 30 June 2013 - 09:37 AM

Thanks, this really helped me understanding environments. Now I see how they can be useful.
But, Im a tad confused this part:
if type(setter) ~= "function" then
        setter(v)
end

Im hoping it that should be this (Otherwise Im confused):
if type(v) ~= "function" then
    setter(v)
end
or:
if type(setter) == "function" then
    setter(v)
end

Other then that, a good tutorial :)

#3 Dlcruz129

    What's a Lua?

  • Members
  • 1,423 posts

Posted 30 June 2013 - 10:31 AM

Good job!

#4 Bordo_Bereli51

  • Members
  • 9 posts

Posted 04 July 2013 - 01:11 PM

great job

#5 ElvishJerricco

  • Members
  • 803 posts

Posted 04 July 2013 - 10:58 PM

View PostEngineer, on 30 June 2013 - 09:37 AM, said:

Thanks, this really helped me understanding environments. Now I see how they can be useful.
But, Im a tad confused this part:
if type(setter) ~= "function" then
		setter(v)
end

Im hoping it that should be this (Otherwise Im confused):
if type(v) ~= "function" then
	setter(v)
end
or:
if type(setter) == "function" then
	setter(v)
end

Other then that, a good tutorial :)

Oh hey what do you know. Thanks. Fixed.

#6 lieudusty

  • Members
  • 419 posts

Posted 05 July 2013 - 04:20 PM

Great tutorial! :)

#7 cdel

  • Banned
  • 496 posts
  • LocationMelbourne, Australia

Posted 13 October 2014 - 09:28 AM

Just to Clarify: If I were to load an api within a program environment, would another program be able to access the loaded api's or are they environment specific?

#8 ElvishJerricco

  • Members
  • 803 posts

Posted 13 October 2014 - 01:37 PM

View Postconnordelaneyy, on 13 October 2014 - 09:28 AM, said:

Just to Clarify: If I were to load an api within a program environment, would another program be able to access the loaded api's or are they environment specific?

Depends on the way you do it.
EDIT: Unless you just mean somewhere within a function that's had its environment set, you call os.loadAPI. In that case, yea that will have the same result as normally calling os.loadAPI, unless the environment the function is in overrides the os table with a custom one that has a custom loadAPI function.

Edited by ElvishJerricco, 13 October 2014 - 03:09 PM.






2 user(s) are reading this topic

0 members, 2 guests, 0 anonymous users