Jump to content




Local variables by default

computer lua

12 replies to this topic

#1 ViperLordX

  • Members
  • 43 posts
  • LocationEarth

Posted 10 February 2016 - 04:44 AM

Hello, fellow programmers! Have you become tired of the Lua variables being global by default? Well, I present unto you thirteen glorious lines of code which should be run upon the startup of a computer. They will not completely disable global variables, but make all variables local by default in any program run after it. If you must, you can still set global variables by doing _G.varname = "value," but doing varname = "value" will define a local variable as opposed to a global one. I've tested this with multiple complex programs, and it has caused no issues thus far and will hopefully solve quite a few problems with colliding variables. So here are my thirteen lines of code which will save you plenty of time and trouble. Simply run it on startup and it'll work its magic.

local oldload = load
function _G.load(str, arg1, arg2, arg3)
  local func = oldload(str, arg1, arg2, arg3)
  local env = getfenv(func)
  if (env == _G) then
	env = {}
  end
  setmetatable(env, {__index = _G, __newindex =
  function(table, var, val)
	rawset(env, var, val)
  end})
  return func
end


#2 Creator

    Mad Dash Victor

  • Members
  • 2,168 posts
  • LocationYou will never find me, muhahahahahaha

Posted 10 February 2016 - 10:21 AM

View PostViperLordX, on 10 February 2016 - 04:44 AM, said:

Hello, fellow programmers! Have you become tired of the Lua variables being global by default? Well, I present unto you thirteen glorious lines of code which should be run upon the startup of a computer. They will not completely disable global variables, but make all variables local by default in any program run after it. If you must, you can still set global variables by doing _G.varname = "value," but doing varname = "value" will define a local variable as opposed to a global one. I've tested this with multiple complex programs, and it has caused no issues thus far and will hopefully solve quite a few problems with colliding variables. So here are my thirteen lines of code which will save you plenty of time and trouble. Simply run it on startup and it'll work its magic.

local oldload = load
function _G.load(str, arg1, arg2, arg3)
  local func = oldload(str, arg1, arg2, arg3)
  local env = getfenv(func)
  if (env == _G) then
	env = {}
  end
  setmetatable(env, {__index = _G, __newindex =
  function(table, var, val)
	rawset(env, var, val)
  end})
  return func
end

Isn't env the same as _G for a given function?

#3 KingofGamesYami

  • Members
  • 3,002 posts
  • LocationUnited States of America

Posted 10 February 2016 - 04:10 PM

View PostCreator, on 10 February 2016 - 10:21 AM, said:

Isn't env the same as _G for a given function?

Yes, but comparing the two will return false.

local function test() end
getfenv( test ).randomvariable = true
print( randomvariable )
print( getfenv( test ) == _G )

Edited by KingofGamesYami, 10 February 2016 - 04:30 PM.


#4 Creator

    Mad Dash Victor

  • Members
  • 2,168 posts
  • LocationYou will never find me, muhahahahahaha

Posted 10 February 2016 - 07:37 PM

So, its not truly local?

#5 apemanzilla

  • Members
  • 1,421 posts

Posted 10 February 2016 - 08:00 PM

Few problems.

1. Will behave differently than normal load() if a syntax error is encountered.

2. Doesn't handle loadfile, loadstring, or dofile.

3. No sanity checking.

#6 CometWolf

  • Members
  • 1,283 posts

Posted 10 February 2016 - 08:28 PM

While this is a great idea, i personally feel it should be restricted to a per-program basis instead of being applied globally. Here's how i do it.
setfenv(
  1,
  setmetatable(
    {},
    {
	  __index = _G
    }
  )
)

For the record, your __newindex entry isn't nessacary as new entries would be assigned to env anyways. Hell most of your code isn't nessacary actually, as load already accepts an environment argument by default.
local load = _G.load
_G.load = function(str, name, mode, env)
  return load(str, name, mode, env or setmetatable({},{__index = _G}))
end

Do note however that both your implementation, as well as mine, prevent access to the shell API as it is not stored in _G.

To be honest im confused as to how your implementation works in the first place, provided getfenv() returns _G you never set the functions environment to env.

#7 apemanzilla

  • Members
  • 1,421 posts

Posted 10 February 2016 - 08:44 PM

View PostCometWolf, on 10 February 2016 - 08:28 PM, said:

While this is a great idea, i personally feel it should be restricted to a per-program basis instead of being applied globally. Here's how i do it.
setfenv(
  1,
  setmetatable(
	{},
	{
	  __index = _G
	}
  )
)

For the record, your __newindex entry isn't nessacary as new entries would be assigned to env anyways. Hell most of your code isn't nessacary actually, as load already accepts an environment argument by default.
local load = _G.load
_G.load = function(str, name, mode, env)
  return load(str, name, mode, env or setmetatable({},{__index = _G}))
end

Do note however that both your implementation, as well as mine, prevent access to the shell API as it is not stored in _G.

To be honest im confused as to how your implementation works in the first place, provided getfenv() returns _G you never set the functions environment to env.

His code works because he getfenv's the function and then manipulates the table. He's using a weird setup - load from 5.2 and getfenv from 5.1...

#8 ViperLordX

  • Members
  • 43 posts
  • LocationEarth

Posted 10 February 2016 - 08:47 PM

Thank you all for your help! CometWolf, I tried your code and it doesn't seem to work, but I did update mine.

local oldload = load
function _G.load(str, arg1, arg2, arg3)
  local func,err = oldload(str, arg1, arg2, arg3)
  if not (func) then
    return func, err
  end
  local env = getfenv(func)
  if (env == _G) then
    env = {}
  end
  setmetatable(env, {__index = _G})
  setfenv(func, env)
  return func,err
end
loadstring = load


#9 apemanzilla

  • Members
  • 1,421 posts

Posted 10 February 2016 - 08:59 PM

View PostViperLordX, on 10 February 2016 - 08:47 PM, said:

Thank you all for your help! CometWolf, I tried your code and it doesn't seem to work, but I did update mine.

...

You still have a weird amalgamation of Lua 5.2 and 5.1 by using load and getfenv. Choose one (preferably 5.2) and stick with it.

Edited by apemanzilla, 10 February 2016 - 08:59 PM.


#10 ViperLordX

  • Members
  • 43 posts
  • LocationEarth

Posted 10 February 2016 - 09:06 PM

Well, I need to override both load and loadstring, right? I'll need to mix 5.1 and 5.2 either way.

#11 CometWolf

  • Members
  • 1,283 posts

Posted 10 February 2016 - 09:09 PM

View Postapemanzilla, on 10 February 2016 - 08:44 PM, said:

His code works because he getfenv's the function and then manipulates the table. He's using a weird setup - load from 5.2 and getfenv from 5.1...
He getfenv's the functions environment table and stores it in the variable env yes, but if it's equal to _G, he sets the variable env to an empty table and then proceeds to change that table's metatable instead of the functions environment table. His recent update correctss that however, using setfenv on the function afterwards.

View PostViperLordX, on 10 February 2016 - 08:47 PM, said:

CometWolf, I tried your code and it doesn't seem to work
That's strange, it seems to work fine for me. I assume you're refering to the simplifed overload of _G.load?

Attached Thumbnails

  • Attached Image: Skjermbilde.JPG

Edited by CometWolf, 10 February 2016 - 09:10 PM.


#12 ViperLordX

  • Members
  • 43 posts
  • LocationEarth

Posted 10 February 2016 - 09:40 PM

Yes, I am.

#13 ViperLordX

  • Members
  • 43 posts
  • LocationEarth

Posted 11 February 2016 - 01:11 AM

Ok, I updated my code again so that shell will appear in the environments.

local oldload = load
function _G.load(str, arg1, arg2, arg3)
  local func,err = oldload(str, arg1, arg2, arg3)
  if not (func) then
    return func, err
  end
  local env = getfenv(func)
  for k, v in pairs(env) do
    _G[k] = v
  end
  if (env == _G) then
    env = {}
  end
  setmetatable(env, {__index = _G})
  setfenv(func, env)
  return func,err
end
loadstring = load







1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users