|
Idk if I consider this a proposal or not, but
what if environments had stacks? For example, let's say we add a new keyword "setsenv" (set scope environment), and another one "getsenv" (get scope environment) (keywords that act like functions? yeah I like that :P), and we have some code like this: print("outside scope", getsenv) do setsenv {print=print, tostring=tostring} -- setting tostring would be needed as print would act on the current env print("inside scope", getsenv) end print("outside scope, again", getsenv) This would output bytecode like this: (pseudobytecode) GETGLOBAL "print" 0 LOADK "outside scope" 1 GETENV 2 CALL 0 2 0 -- call function at 0 with 2 arguments, put results starting from 0 -- some table boilerplate PUSHENV 0 GETGLOBAL "print" 0 LOADK "inside scope" 1 GETENV 2 CALL 0 2 0 POPENV -- caused by "end" in "do...end" GETGLOBAL "print" 0 LOADK "outside scope, again" 1 GETENV 2 CALL 0 2 0 Q: Why would this be good? A: 1. print()'s tostring() calls wouldn't depend on the "global globals" (that is, the "global environment", as stored in the C registry), but rather on the callers' currently active environment. 2. string metatable hacks for sandboxing would be possible like in Lua 5.1.[1] 3. other cool stuff[?] Q: What about loading bytecode that pops the environment stack multiple times? A: Environment stacks are per closure, not global. -- Disclaimer: these emails are public and can be accessed from <TODO: get a non-DHCP IP and put it here>. If you do not agree with this, DO NOT REPLY. [1]: This is just an example and I don't remember the right values so the getfenv offsets might be wrong, but basically this is the code: local globalstringmetatable = getmetatable'' debug.setmetatable('', { __index = function(t,k) local x = getmetatable(getfenv(2)) if type(x) == "table" and rawget(x, "__stringmt") then local y = rawget(rawget(x, "__stringmt"), "__index") if type(y) == "table" then return y[k] elseif type(y) == "function" then return y(t,k) elseif y == nil then local y = rawget(globalstringmetatable, "__index") if type(y) == "table" then return y[k] elseif type(y) == "function" then return y(t,k) else error("Attempt to index a string value", 2) end else error("Attempt to index a string value", 2) end end end }) |