lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 31.03.2014 01:09 schröbte Tim Hill:

[...]

To my mind “the Lua way” is have as LITTLE policy as is practical.
The question, therefore, is really this: is it sufficiently useful to
have a policy-based method to manage global variable declaration to
justify it’s addition? Notice that this has nothing to do with HOW
such a policy is realized. This is because policies solve issues of
standardization, while the realization of policies involve issues of
efficiency and compatibility (and, dare i say it, elegance).

The OP points out that the problem with existing
implementations/work-arounds/hacks (choose your word) is that they
all collide with 3rd party code such as libraries. I’ve had this
issue as well; it doesn’t really matter what you do with the existing
solutions, they only really work if you have total control of 100% of
the source in your project.

That's not true. It's just that the `strict.lua` provided by the Lua authors *as an example* does not handle that case (to keep it simple, I guess). You can have each module author choose the method he/she wants to use to catch unwanted globals, no policy needed here at all. This is obviously true for static offline approaches, and for the dynamic approaches I've thrown together and attached a proof of concept based on the original `strict.lua`. Use it via

    require 'mstrict'()  -- notice the extra pair of parentheses

in every file you want to. No third party modules are harmed in the process. Global assignments at the top level still count as declarations. Have fun!


[...]

—Tim


Philipp

-- modified/modular strict.lua
-- distributed under the Lua license: http://www.lua.org/license.html

local assert = assert
local V = assert( _VERSION )
local _G = assert( _G )
local error = assert( error )
local setmetatable = assert( setmetatable )
local setfenv = assert( V ~= "Lua 5.1" or setfenv )
local require = assert( require )
local debug = require( "debug" )
local d_getinfo = assert( debug.getinfo )
local d_setupvalue = assert( V == "Lua 5.1" or debug.setupvalue )

local declared = {}
local meta = {}
local strict_G = setmetatable( {}, meta )

local function what()
  local d = d_getinfo( 3, "S" )
  return d and d.what or "C"
end

function meta.__newindex( _, n, v )
  if _G[ n ] == nil and not declared[ n ] then
    local w = what()
    if w ~= "main" and w ~= "C" then
      error( "assign to undeclared variable '"..n.."'", 2 )
    end
    declared[ n ] = true
  end
  _G[ n ] = v
end

function meta.__index( _, n )
  local v = _G[ n ]
  if v == nil and not declared[ n ] and what() ~= "C" then
    error( "variable '"..n.."' is not declared", 2 )
  end
  return v
end

return function()
  if V == "Lua 5.1" then
    setfenv( 2, strict_G )
  elseif V == "Lua 5.2" or V == "Lua 5.3" then
    local info = d_getinfo( 2, "f" )
    d_setupvalue( info.func, 1, strict_G )
  else
    error( "unsupported Lua version", 2 )
  end
end