lua-users home
lua-l archive

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


On Wed, Feb 24, 2010 at 6:38 PM, Roberto Ierusalimschy wrote:
> After that long discussion about setfenv/getfenv, we are convinced
> that both functions should belong to the debug API. Both clearly break a
> function's abstraction, tampering with the "original meaning" of the
> function.

In [1], one of the recurring problems was the desire to change the
environment lexically on a block or expression, but Lua 5.1 only
allowed the environment to be changed on a per-function basis.  This
necessitated messing with the environment of the enclosing function
(possibly dangerous) or defining a nested function to apply that
environment to (more costly and verbose, though cleaner):

  local o = with(shape)( rectangle { point(0,0), point(3,4) }
):endwith() -- modify outer env
  local o = with(shape)(function() return rectangle { point(0,0),
point(3,4) } end)  -- modify inner env

The _ENV or in/do proposals eliminate that restriction, at least on
blocks, leaving us with

  local o
  do
    local _ENV = with(shape)
    o = rectangle { point(0,0), point(3,4) }
  end

Another case of this is, as I sometimes see, placing two modules or
classes into the same chunk (without enclosing anonymous functions to
separate the two):

  module("one", package.seeall)
  function a() <code1> end
  module("two", package.seeall)
  function b() <code2> end

Determining how that behaves requires some thought because the
environment of the enclosing chunk dynamically changes.  A cleaner
design might have been something like similar to the previous example:

  local one = module("one", _G, function()
    local x = 1
    function a() print(x); x=x+1 end
  end)
  local two = module("two", _G, function()
    function b() print "b" end
  end)

So how does the _ENV proposal affect module definition?  This seems
less cohesive:

  local one; do
    local _ENV = module("one", _ENV)
    local x = 1
    function a() print(x); x=x+1 end
    one = _ENV
  end
  local two; do
    local _ENV = module("two", _ENV)
    function b() print "b" end
    two = _ENV
  end

Yet another case for environments (getfenv) is to do string interpolation:

  printf("Hello $name, the value of key $k is $b!\n", _ENV);

Unfortunately, it doesn't grab locals.  It would be nice to have
something analogous like

  local a,b,k,name = ...
  printf("Hello $name, the value of key $k is $b!\n", _LOCALS);

compile down to bytecode equivalent to

  local a,b,k,name = ...
  local _LOCALS = {a=a,b=b,k=k,name=name}
  printf("Hello $name, the value of key $k is $b!\n", _LOCALS);

I think someone recommended something like that recently.  Though it's
possible to do via the debug library, it's also possible to do merely
by compile-time transformation like the above.  That's provided you
don't have too many locals, so maybe full scale macros are preferred.

[1] http://lua-users.org/wiki/TableScope
[2] http://lua-users.org/wiki/StringInterpolation