[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: scoping rules
- From: Roberto Ierusalimschy <roberto@...>
- Date: Thu, 10 Jun 1999 16:42:01 -0300
> Lua is great on almost every point, except the scoping rules. Why can't we
> have normal scoping rules (i.e a variable is local unless defined
> globally?).
What is a "normal" scoping rule? In many languages (AWK, Snobol, Perl, etc)
a variable is global unless declared local. Most other languages (C, C++,
Pascal and its heirs, Haskell, Lisp, etc) do need global and local
declarations, but we usually only care for the locals when reading a
program. In C, for instance, when you read inside a function something like
varname = 1;
you do not go all over the file (and includes) to see whether "varname" is
declared as global. You just check if varname is declared local; if it's
not, then it is a global variable. A compiler does the same, and only
*after* seeing that the variable is not local it will need a global
declaration.
Very few languages do create local variables without some kind of explicit
declarations. This is because local variables are local to a given scope,
and so we must specify this scope. If we get the rule that "a variable is
local unless defined globally", we will have some weird behaviours; for
instance, in Lua (and also in C and Java) the scope of a variable is not a
whole function, but the inest block where the variable is declared. So, if
you write something like
if a then i=1 else ... end
the scope of the variable 'i' (now local by default) would be only the
"then" part of the if!! (the inner block...)
In Lua you do not need global declarations. You can complain about this
(and many people do); but to assume that a variable without this global
declaration should be automatically considered local does not look "normal"
to most languages, and certanly is not the right way to solve the problem
with undeclared global variables.
If the real problem is the use of global variables without declaration,
there is an easy and efficient way to solve that, using tag methods. The
idea is to set the tag methods 'getglobal' and 'setglobal' over the tag nil
(which is the value of any "undeclared" variable), and to keep a table with
the name of all declared global variables. When you read or write a nil
global variable, the tag method goes to the table to check whether the
variable has been declared. When you read or write a non-nil global, the
most frequent case, there is no cost at all.
==================================================================
_Globals = {} -- a set to keep the names of global variables
function declare (globalname)
_Globals[globalname] = 1
end
function undeclare (globalname) -- optional
rawsetglobal(globalname, nil)
_Globals[globalname] = nil
end
settagmethod(tag(nil), 'setglobal', function (name, oldvalue, newvalue)
if not _Globals[name] then
error("cannot write undeclared variable `"..name.."'")
end
return rawsetglobal(name, newvalue)
end)
settagmethod(tag(nil), 'getglobal', function (name, value)
if not _Globals[name] then
error("cannot read undeclared variable `"..name.."'")
end
return value -- or nil (value must be nil...)
end)
==================================================================
Example:
> dofile'temp' -- the above code
> print(i)
lua: cannot read undeclared variable `i'
Active Stack:
function error [in file (C)]
`getglobal' tag method [in file temp]
main of (dostring) >> "print(i)"
> declare'i'
> print(i)
nil
> i=10
> print(i)
10
> a = 10
lua: cannot write undeclared variable `a'
Active Stack:
function error [in file (C)]
`setglobal' tag method [in file temp]
main of (dostring) >> "a = 10"
> undeclare'i'
> i='hello'
lua: cannot write undeclared variable `i'
Active Stack:
function error [in file (C)]
`setglobal' tag method [in file temp]
main of (dostring) >> "i='hello'"
-- Roberto