[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Implicit Globals - A compile time solution.
- From: "John Hind" <john.hind@...>
- Date: Tue, 19 Feb 2008 15:30:20 -0000
[Previous attempt was unreadable ? trying again]
Sorry to raise the issue of implicit globals yet again. The trouble is that
Lua is such an elegantly designed language that this one little imperfection
keeps nagging away at one! Roberto recognises the problem in "Programming in
Lua" and suggests a few run-time fixes. However I would like to suggest a
compile-time fix which might solve the problem more elegantly.
At the moment, when the statement "x = x" (this is a contrived example for
illustration, I mean any variable reference except in a local statement) is
compiled, the two references to 'x' are resolved by first checking as a
local variable, then as an upvalue and as a last resort compiling the
statement as "getfenv()['x'] = getfenv()['x']" which postpones resolution to
run-time. This gives the behaviour of implicitly creating a global variable
unless it is explicitly declared, somewhere in the lexical containment
structure, as local.
My suggestion is that the compiler should continue to resolve *access*
reference as it does at the moment, but *assignment* reference should be
changed. As currently, first 'x' would be checked as a local and then as an
upvalue, but if this does not resolve it would be created as a *local*. So
in effect "x = x", when 'x' has not already been declared local, would be
compiled as "local x = getfenv()['x']". To assign to or create a global
variable one must now write, for example, "_G.x = x". However note that one
can still *access* a global variable without the prefix, so library
functions and modules are not broken.
This suggestion simplifies the language by eliminating the "local" keyword
(except for the esoteric case of overriding an upvalue), regularises it by
lexically scoping variables by default and solves the issue of accidental
pollution of the global namespace without requiring "option explicit" or
run-time protection mechanisms. "Naive" code will tend to be more efficient
since chunk-level locals resolved at compile-time will intuitively replace
globals resolved at run-time. Furthermore backward compatibility is
maintained in most everyday cases, probably only breaking some module or
library files. A directive could be provided to ease transition by
specifying old or new behaviour for a given compilation chunk.
If this is controversial, could it maybe be considered as a patch, compile
time, or C API switch so it could be experimented with prior to a decision
on final adoption? However, unless I've missed something, I cannot see any
serious downside with this solution, except of course for migration issues.