lua-users home
lua-l archive

Re: local variables and scope

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


Hi,
I used Lua for some years and I'm currently in need of 
explicit global declarations.
Roberto Ierusalimschy wrote:
> Follows a nice script to detect missing "local" declarations and other
> "wrong" uses of global variables.
> 
> Simply put it in your path and add require"strict" to your program
> (or call "lua -lstrict").
Your code looks good, but I want to declare every global variables explicitly, 
in all of my Lua code. Also, I want to allow nil values for globals.
So I made up an another alternative, including several part of your idea.
features
- explicit global declarations by,
 global "myvar"
- global variables can be nil
 (implicitly declared global variables are automatically registered as "declared")
- user can select implicit or explicit variable declaration on main chunk
 (default behavior is : "allow implicit declaration on main chunk")
- explicit declarations can be "off" by calling use_implicit_globals()
- functions can implicitly declared only on main chunk
- if you want to run "explicitly" created lua codes without this module, 
 just define these functions to avoid any error.
 function global() end
 function use_explicit_globals() end
 function use_implicit_globals() end
A declaration is implicit or explicit, depending on where the 
declaration occurs. (extending Roberto's logic)
---------------------------- C | main chunk | other(in function)
-------------------------------------------------------------------------
normal Lua ----------------- implicit | implicit | implicit
use_explicit_globals() ----- implicit | implicit | explicit
use_explicit_globals(true) and
-----value is not function - implicit | explicit | explicit
---------value is function - implicit | implicit | explicit
some drawbacks:
- it may leads to bad condition if user change the global table manually by setfenv.
- an implicitly-declared-global-variables, which value is nil 
 when use_explicit_globals() is called, can't be registered.
Any feedback is welcome.
----------- example ------------
require "explicit_globals"
use_explicit_globals(true) -- use explicit declaration, even for main chunk
--- OK case
global "my_global_variable"
my_global_variable = 1
local a = my_global_variable
--- NG case
my_undeclared_variable = 1 -- NG
local a = my_undeclared_variable2 -- NG
--- functions declarations
function undeclared_global_func() end --- ok
undeclared_global_func2 = function() end --- ok
function test()
 global "my_global_func"
 function my_global_func() end --- ok
 function undeclared_global_func3() end --- NG
end
test()
----------- explicit_globals.lua ------------
-- table for checking global var declaration
local gdef = {}
local gdef_enabled = nil
-- the function to define global vars
function global(n)
 if not gdef_enabled then
 error("calling function global() when explicit-globals not enabled",2)
 end
 if gdef[n] == true then
 error("re-definition of global \"" .. tostring(n) .. "\"",2)
 end
 gdef[n] = true
 return
end
local function registerglobal(t,n,v)
 gdef[n] = true
 rawset(t,n,v)
end
-- forbid implicit definition of global vars
function use_explicit_globals( is_explicit_in_main_chunk )
 -- set metatable for gloval environment
 local mt = getmetatable(_G)
 if mt == nil then
 mt = {}
 setmetatable(_G, mt)
 end
 -- include implicitly-declared globals in gdef table, 
 -- in case some of it becomes nil and __index,__newindex be called.
 -- drawback: if the value is nil now, it will not be included.
 for k,v in pairs(_G) do
 gdef[k] = true
 end
 mt.__newindex = function (t,n,v)
 if gdef[n] ~= nil then -- declared global
 rawset(t,n,v);return
 end
 local w = debug.getinfo(2,"S").what
 if w == "C" then -- in C chunk
 registerglobal(t,n,v);return
 end
 if ( not is_explicit_in_main_chunk and w == "main" ) then -- in main chunk
 registerglobal(t,n,v);return
 end
 if type(v) == "function" then
 -- funtcion value
 if w == "main" then 
 -- declatration of functions in main chunk is ok.
 registerglobal(t,n,v);return
 else
 error("assignment of undeclared global function \"" .. tostring(n) .. "\" outside of main chunk. use global(\"var\", val)", 2)
 end
 else
 -- not function value
 error("assignment of undeclared global \"" .. tostring(n) .. "\". use global(\"var\", val)", 2)
 end
 end
 mt.__index = function (t,n)
 if gdef[n] == nil and debug.getinfo(2,"S").what ~= "C" then
 error("attempt to use undeclared global \"" .. tostring(n) .. "\". use global(\"var\", val)", 2)
 end
 return rawget(t, n)
 end
 gdef_enabled = true
end
-- back to normal, implicit global declaration.
function use_implicit_globals()
 local mt = getmetatable(_G)
 if mt ~= nil then
 mt.__newindex = nil
 mt.__index = nil
 end
 gdef_enabled = nil
end
----------- explicit_globals.lua ------------
-- 
Makoto Hamanaka <naraxx800@yahoo.co.jp>

AltStyle によって変換されたページ (->オリジナル) /