This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
KaoS's profile picture

Function environments

Started by KaoS, 16 March 2013 - 04:14 PM
KaoS #1
Posted 16 March 2013 - 05:14 PM
Hi pros, I have been fiddling a lot with environments and their uses and have run into a bit of a roadblock… it seems like local vars OUTSIDE a function override its environment.


function test()
  print(a)
end

is a basic function, if I call test() it will print nil. then if I say

setfenv(test,{a="testmessage",print=print})
and call the function again it will print "testmessage" which makes sense however if I say

local a="defaultmessage"
function test()
  print(a)
end
setfenv(test,{a="testmessage",print=print})
and call test() it will print "defaultmessage" when a="testmessage" in that function

does anyone know why this is, if it should be like that and if there is a way to correct it?
Edited on 16 March 2013 - 05:09 PM
JokerRH #2
Posted 17 March 2013 - 01:06 AM
They are both in the same fenv. I don't know if they actually overwrite each other, but if lua has a local and a normal variable it's going to use the local first.
But since they both have the same variable name, check it like this:

for ind, param in pairs(getfenv()) do print(ind) end
If the variable has been overwritten, it should appear if you run this function.
Otherwise: remove the local and it should work
KaoS #3
Posted 17 March 2013 - 01:31 AM
they shouldn't be in the same fenv though because I setfenv it a new environment which replaces the old one, all vars should have to be in the environment to work which is why I have to include print=print in the fenv or it will not have the print command…

if I run that function (I have to add getfenv and pairs to the env to run it in the function though) it prints

a
print
getfenv
pairs
JokerRH #4
Posted 17 March 2013 - 01:58 AM
Maybe try it like this:

function func()
  a = "defaultmessage"

  function test()
    print(tostring(a))
  end
end

--Set a new enviroment and run the function
local env = setmetatable({}, {__index = _G})
setfenv(func, env)
func()
--> env.a = "defaultmessage"

env.a = "testmessage"
env.test()
immibis #5
Posted 17 March 2013 - 02:02 AM
Local variables aren't stored in the environment. They take precedence over global variables with the same name.
lieudusty #6
Posted 17 March 2013 - 04:28 AM
I think its because a is a local variable and lua uses the local variable over the global one. (I'm just guessing :P/>)
JokerRH #7
Posted 17 March 2013 - 04:34 AM
I think its because a is a local variable and lua uses the local variable over the global one. (I'm just guessing :P/>)
Already posted :P/>
They are both in the same fenv. I don't know if they actually overwrite each other, but if lua has a local and a normal variable it's going to use the local first.

Anyways, @Kaos: I think it should be because it doesn't accept the new enviroment. Sounds weird, haven't fully understood that, too, but if you have the function and you set the new enviroment, the functions inside the function still remain their old fenv, therefor there is still the local a. (Even though you overwrote the fenv)

Edit: Just wrote a little programm that will explain it to you. Copy and paste it to a file and run it and it should give you an idea of what is the problem…
Spoiler


function set(color)
  if term.isColor() then term.setTextColor(color) end
end

--This is the function we create the fenv for
function a()
  a = "Testvar"

  function a1()
    print(a)
  end

  function a2(param)

  end
end

local env = setmetatable({}, {__index = _G})
setfenv(a, env)
a()

print("This is the native a.a")
set(colors.red)
env.a1()
set(colors.white)

print()
print("This is the native fenv")
set(colors.green)
for ind, param in pairs(getfenv(a)) do print(ind) end
set(colors.white)

local newEnv =  {print = print, a = "Demovar"}
setfenv(a, newEnv)

print()
print("This is the (theoretically) modified a.a")
set(colors.red)
env.a1()
set(colors.white)

print()
print("This is the new fenv")
set(colors.green)
for ind, param in pairs(getfenv(a)) do print(ind) end
set(colors.white)

print()
print("This is the new fenv of a.a1")
set(colors.green)
for ind, param in pairs(getfenv(newEnv.a1)) do print(ind) end
set(colors.white)
KaoS #8
Posted 17 March 2013 - 08:32 AM
Local variables aren't stored in the environment
are they not even linked to it in any way? otherwise how does a local var in a function remain local to that function? seems… unintuitive


I think its because a is a local variable and lua uses the local variable over the global one. (I'm just guessing :P/>)
you are correct in that however in my personal (and I realize unimportant) opinion if they are not in the function then they should be part of the global program's fenv and inherited by the function, if you change the fenv they should no longer inherit


Maybe try it like this:

function func()
  a = "defaultmessage"

  function test()
	print(tostring(a))
  end
end

--Set a new enviroment and run the function
local env = setmetatable({}, {__index = _G})
setfenv(func, env)
func()
--> env.a = "defaultmessage"

env.a = "testmessage"
env.test()
that would work perfectly… the issue is local vars though

anyways I think I have my answer… Lua local vars are not linked to the fenv, it is just how it works and must be accepted
JokerRH #9
Posted 17 March 2013 - 10:44 AM
they should be part of the global program's fenv and inherited by the function, if you change the fenv they should no longer inherit

You didn't change the fenv. I posted some code above that should have underlined that.
(It's the spoiler)
Lua acts strange it that thing… :D/>
KaoS #10
Posted 17 March 2013 - 05:06 PM
trust me… I do. I understand your example however yours will never work because you need to change the fenv on env.a1 not a, env.a1 inherits the fenv from a BUT it stops doing so when you change a's fenv. check this example


function a()
myvar="hi"
function b()
  print(myvar)
end
end
a()
b()
getfenv(a).myvar="me"
b()
will print "hi" and then "me" HOWEVER

function a()
myvar="hi"
function b()
  print(myvar)
end
end
a()
b()
setfenv(a,{myvar="me"})
b()
will print "hi" twice because b() only inherits the default fenv of a, if you change a's fenv then b gets disconnected from it