lua-users home
lua-l archive

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


On Wed, Jul 21, 2010 at 11:43, Stuart P. Bentley <stuart@testtrack4.com> wrote:
> On Fri, 16 Jul 2010 12:38:32 -0400, Roberto Ierusalimschy
> <roberto@inf.puc-rio.br> wrote:
>
>> Repeating again: the point is not to disallow global access, but to
>> prevent unintended creation of globals. Changing the environment
>> prevents the unintended creation of globals, but at a high cost (no
>> more access to globals including the standard libraries):
>>
>> do
>>  local _ENV = nil
>>  a = 12345    --would result in "error: no environment"; fine
>>  local a = 12 -- fine, 'a' now is local
>>  print(a)     -- oops; error...
>> end
>>
>> -- Roberto
>>
>>
>
> What about this?
>
> do
>  local G = _ENV -- save the environment in a local G
>
>  local _ENV = nil -- remove the reference to the global table as environment
>
>  G.a = 12345 -- "global variables" would just be explicit indexes -
>              -- the downside would be that any use of the global "a" would
> need
>              -- a couple characters before every use, but if the developer
> chose to
>              -- remove the environment, it's safe to say they're OK with
> that,
>              -- and if they have to use globals a lot again in one section
>              -- of the code they can just enclose it within a "do local _ENV
> = G ... end"
>
>  local a = 12 -- all plain references to "a" unambiguously point to this
> local
>
>  -- Now, two ways to access print and all other globals including the
> standard libraries:
>  G.print(a) -- explicitly index it out of the global table
>
>  -- or --
>
>  local print = G.print -- or local print = print if you do it before
>                         -- removing the environment
>  print(a)
>
> end
>
> Module authors have been using these two approaches (explicit indexing and
> localization) for years without complaint.
>
>

I think a lot of the suggestions made so far are basically syntactic
sugar for this. If you're using a lot of functions from the global
namespace it'd be somewhat annoying to have to do "local print, io,
string, table = G.print, G.io, G.string, G.table" etc all the time.

Perhaps a solution here is a "_module" table, which works similar to
_G, containing all modules that have been loaded to the global
namespace. i.e. at startup it would contain {string, os, io} etc as
well as perhaps some of the built-in globals like print, package, and
pcall (or perhaps these should be in modules of some sort as well).

The problems I can see with this are how to keep track of the module
tables - with the current system a module isn't required to return
itself to a require() call, and can just toss as many tables into the
global namespace as it likes; we'd have to catch those tables and make
references to them in _module. There's also the possible issue of
opening up another "backdoor" to io, os etc to sandboxed scripts
written for 5.1, but it should only take a few lines to fix that (even
just setting _module to nil).

For the former problem, maybe require() can just add any globals that
are present after loading the module that weren't before. This might
catch a few globals-that-should-be-locals, but I guess that's just
another reason to encourage proper use of locals. :-)

-- 
Sent from my toaster.