lua-users home
lua-l archive

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


On 3 August 2010 15:43, David Manura <dm.lua@math2.org> wrote:
> On Mon, Aug 2, 2010 at 12:55 PM, Jerome Vuarand
> <jerome.vuarand@gmail.com> wrote:
>> [code approximately as follows]
>> local _M = {}; local _ENV = setmetatable({},{__index=_ENV, __newindex=_M}); function foo() _M.bar() end; function bar() print'!' end; return _M
>
> I haven't found it advantageous to merge the _G table and a module's
> public table into the same top-level global namespace because Lua
> doesn't perfectly support the concept of there being *two*
> simultaneous environment tables (e.g. _ENV1 and _ENV2 [1] or
> package.clean [2]).  Lua does, however, support one environment table
> sharing the top-level namespace with local variables, which leads to
> some variant of these four approaches:
>
>  local M = {}; function M.foo() M.bar() end; function M.bar()
> print'!' end; return M
>  local function bar() print '!' end; local function foo() bar() end;
> return {foo=foo, bar=bar}
>  local _G = _ENV; _ENV={}; function foo() bar() end; function bar()
> _G.print'!' end; return _ENV
>  local print=print; _ENV={}; function foo() bar() end; function bar()
> print'!' end; return _ENV
>
> IMO, the these are fine semantically, with the first one being the
> simplest and the second being the most efficient.  However, if you'd
> like, you could devise ways for Lua to shorten them.  For example, let
> `require` build a private environment {__index = _G, M = {}}, to avoid
> the `local M = {}; ..... return M` boilerplate or make _M be a macro
> that auto-expands to a table of all local functions except "private"
> functions prefixed by '_'.
>
> But here's another, IMO practical, idea along the lines of supporting
> "two simultaneous environment tables":
>
>  _ENVW,  = {}
>  _ENV = _G  -- this line actually can be omitted but is included for clarity
>  function foo() bar() end
>  function bar() print'!' end
>  return _ENVW   -- Note: rename _ENVW to something friendlier like
> _PUBLIC if you want
>
> What this would mean is that any global variable ever written to
> within the current lexical scope (i.e. foo and bar) would be resolved
> to the _ENVW table for both reads and writes, and all other global
> variables that are only read from would be resolved to _ENV.  So, the
> above becomes bytecode-equivalent to
>
>  local _ENVW = {}
>  local _ENV = _G  -- this line actually can be omitted but is
> included for clarity
>  function _ENVW.foo() _ENVW.bar() end
>  function _ENVW.bar() _ENV.print'!' end
>  return _ENVW
>
> and also has basically the same bytecode as my current preferred method:
>
>  local M = {}; function M.foo() M.bar() end; function M.bar()
> print'!' end; return M
>
> [1] http://lua-users.org/lists/lua-l/2010-07/msg00262.html
> [2] http://lua-users.org/wiki/ModuleDefinition
>

Can this not be done like so?:
local MOD = {}
local _ENV = setmetatable({},{__index=function(t,k) return MOD[k] or
_G[K] end , __newindex=function(t,k,v) MOD[k] = v end })
return MOD