Script to check that you use local variables inside functions

Posted by Nick Gammon on Wed 06 Sep 2006 04:34 AM — 2 posts, 11,631 views.

Australia Forum Administrator #0
I found this nifty code example on the Lua mailing list. It was written by Roberto Ierusalimschy, the developer of Lua.


--
-- strict.lua
-- checks uses of undeclared global variables
-- All global variables must be 'declared' through a regular assignment
-- (even assigning nil will do) in a main chunk before being used
-- anywhere or assigned to inside a function.
--

local mt = getmetatable(_G)
if mt == nil then
  mt = {}
  setmetatable(_G, mt)
end

mt.__declared = {}

mt.__newindex = function (t, n, v)
  if not mt.__declared[n] then
    local w = debug.getinfo(2, "S").what
    if w ~= "main" and w ~= "C" then
      error("assign to undeclared variable '"..n.."'", 2)
    end
    mt.__declared[n] = true
  end
  rawset(t, n, v)
end
  
mt.__index = function (t, n)
  if not mt.__declared[n] then
    error("variable '"..n.."' is not declared", 2)
  end
  return rawget(t, n)
end



What this does is use a metatable on the global (_G) table to make sure that setting variables, or reading them, is only done to "declared" variables. That is, variables that are explicitly mentioned on the global script space.

This helps prevent common errors like misspelling variable names in functions, or accidentally assigning to a global variable when a local one would be more sensible.

Let's assume you save that to disk as "strict.lua".

Some example code:


require "strict"

function f ()
 a = 2 --> error: assign to undeclared variable 'a'
 
 print (b)  --> error:  variable 'b' is not declared
 
 function g ()  --> error:  assign to undeclared variable 'g'
 end -- g
 
end -- f

f ()



A sensible strategy in these cases would be to put "local" in front of variables and functions that are really supposed to only exist inside the scope of the local function.
Amended on Wed 06 Sep 2006 07:49 AM by Nick Gammon
USA #1
Perl programmers out there will recognize this behavior as being very similar to use strict, or, at least, use strict vars. It's very useful for debugging, because it's easy to make a typo in a variable name and cause mysterious and hard-to-find errors.