I'm working on a way to create objects in lua using functions with their own enviroment. (That should mean I create a function that represents my object) It all works great, I can create objects and they are all separate of each other, but I haven't figured out how to extend an object using anotherone.
What I did is I've set a function enviroment and simply added the functions from the other object into it. Unfortiounatly, they do show up if I use getfenv, but they are still bound to their old fenv. That means if I extend a with b and b has the function b.func I can now access it typing a.func, but if a has (native) functions like a.foo I can't access them from a.func
For instance:
a.foo = function() end
b.func = function() foo() end
a.func()
-> error because foo is nil
Is there a way to solve that?
Function enviroments
Started by JokerRH, Mar 15 2013 10:55 AM
9 replies to this topic
#1
Posted 15 March 2013 - 10:55 AM
#2
Posted 15 March 2013 - 12:48 PM
Use a.foo() instead of just foo().
#4
Posted 15 March 2013 - 07:02 PM
It's not the example, it's because if the way function enviroments work. (so it's not a.foo)
My problem is that if I load my function a, every fubction inside it has the same function enviroment. That means if a.funcA sets name = "Test", a.funcB can refer to that variable, just fine. But the previously inserted functions of b
show up in a, so I can call them, but that
function can't refer to name.
(can't post code yet, I'll have school in a few minutes)
Anyone an idea?
My problem is that if I load my function a, every fubction inside it has the same function enviroment. That means if a.funcA sets name = "Test", a.funcB can refer to that variable, just fine. But the previously inserted functions of b
show up in a, so I can call them, but that
function can't refer to name.
(can't post code yet, I'll have school in a few minutes)
Anyone an idea?
#5
Posted 16 March 2013 - 06:29 AM
Have you tried using an __index metatable entry on the "child" environment table to "inherit" values from the "parent" that aren't present in the "child" environment?
#6
Posted 16 March 2013 - 11:01 AM
@Lyqyd: Not exactly. I wrote a little demo program just to show the problem:
Theorethically, objectC contains objectA and objectB, as it can be seen in the functionenviroment.
Practically, all the functions of objectA are in objectC, but still have their own functionenviroment
That's why I can't adress any functions through a.test that originally belong to objectB.
Is there a way to get these two tables of functions (objectA and objectB) to share one fenv (objectC)?
Edit: The effect is more obvious with the two loops I added that will print the different fenvs, but I can't figure out how to solve that...
function a()
function f_a1()
end
function f_a2(param)
end
function test()
print("This is f_a1 from a.test: "..tostring(f_a1))
print("This is f_b1 from a.test: "..tostring(f_b1))
end
end
function b()
function f_b1()
end
function f_b2()
end
end
term.clear()
term.setCursorPos(1, 1)
--Load function a
objectA = setmetatable({}, {__index = _G})
setfenv(a, objectA)
a()
--Load function b
objectB = setmetatable({}, {__index = _G})
setfenv(b, objectB)
b ()
--Create object c that contains both a and b
objectC = {}
for ind, param in pairs(objectA) do
objectC[ind] = param
end
for ind, param in pairs(objectB) do
objectC[ind] = param
end
local func = function() end
setfenv(func, objectC)
--Check the enviroment
print()
print("This is the current enviroment of objectC: ")
if term.isColor then term.setTextColor(colors.green) end
for ind, param in pairs(getfenv(func)) do print(ind) end
if term.isColor then term.setTextColor(colors.white) end
--Trying it
print()
objectC.test()
print()
print("This is the enviroment of f_a1")
if term.isColor then term.setTextColor(colors.green) end
for ind, param in pairs(getfenv(objectC.f_a1)) do print(ind) end
if term.isColor then term.setTextColor(colors.white) end
print()
print("This is the enviroment of f_b1")
if term.isColor then term.setTextColor(colors.green) end
for ind, param in pairs(getfenv(objectC.f_b1)) do print(ind) end
if term.isColor then term.setTextColor(colors.white) end
Theorethically, objectC contains objectA and objectB, as it can be seen in the functionenviroment.
Practically, all the functions of objectA are in objectC, but still have their own functionenviroment
That's why I can't adress any functions through a.test that originally belong to objectB.
Is there a way to get these two tables of functions (objectA and objectB) to share one fenv (objectC)?
Edit: The effect is more obvious with the two loops I added that will print the different fenvs, but I can't figure out how to solve that...
#7
Posted 16 March 2013 - 11:05 AM
they don't have to. metatables will let you make them behave as if they do. B's metatable is set to {__index=A}, and any calls through B will check B first and, failing to find the key, will go on to check A.
#8
Posted 16 March 2013 - 11:08 AM
GopherAtl, on 16 March 2013 - 11:05 AM, said:
they don't have to. metatables will let you make them behave as if they do. B's metatable is set to {__index=A}, and any calls through B will check B first and, failing to find the key, will go on to check A.
That wouldn't work, because if 'a' changes a variable 'b' wants to print, it can't refer to it.
#9
Posted 16 March 2013 - 02:21 PM
Solved. It is so simple right as you get the solution, but it may takes a couple of hours...
For anyone who is interested in it: You just have to set the fenv of both functions to the same table:
For anyone who is interested in it: You just have to set the fenv of both functions to the same table:
--a and b are given functions
--Creating independent functions
newA = a
newB = b
--setting enviroment
local env = setmetatable({}, {__index = _G})
setfenv(newA, env)
setfenv(newB, env)
--load functions
newA()
newB()
--return object
return env
#10
Posted 16 March 2013 - 04:09 PM
Or as an alternate option, write the function that actually gets assigned to __index when you do
Lua - so much crazy lol
local env = setmetatable({}, {__index = _G})
The CraftOS bios actually replaces the native setmetatable with a version that allows you to seemingly assign tables to the __index of a metatable, when in actuality it's creating a method that searched the table for a value and if it isn't nil returns it. You can use this system to access _G as well as other function's environments by using getfenv to retrieve the function's environment, then making __index search it as a part of its checks, then using setfenv on the other function so it's searching two tables when it tries to index it's environment.Lua - so much crazy lol
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users











