lua-users home
lua-l archive

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


On Wed, Oct 19, 2011 at 6:24 PM, Roberto Ierusalimschy
<roberto@inf.puc-rio.br> wrote:
>> Certainly an improvement from handling the module table explicitly
>> (and no segfaults this time). But having basically the same function
>> being provided by the loader[1] would obviate the need for explicitly
>> mentioning _ENV.
>
> I think explicitly mentioning _ENV is good. If you are working with
> a different global environment, why hide that information?

Fair. I could argue otherwise, but that's indeed more a matter of
taste, which I respect.

One remaining issue lies in the visibility of globals:

David Manura wrote:
>> Hisham wrote:
>> The module() function gave us an easy answer for the question "how do
>> I write a module" that mirror other languages that offer constructs for modularity.
>> [...] If module() is broken beyond repair and there is no clean way to add a
>> library function to do that, I'd dare to say that this is something
>> important enough that a language construct would be justifiable
>
> OTOH, there are multiple ways to use this function: The somewhat
> canonical "easy way" involves package.seeall, and maybe we should all
> just accept that, in the way in another life I just accept Perl 5.
> Josh's principle I think is important though: "[it's about] making it
> easier to do the right thing. With module it's easy to get things
> wrong".

Many of the complaints against module() are actually against
package.seeall. The issues of exposing unrelated globals through a
module and inheriting dependencies are caused by it. The module()
implementation you suggested leaves this question open, so my
suggestion in that front would be something along the lines of:

---------- variation on Roberto's module
function module (name, ...)
 local env = package.loaded[name]
 if env == nil then
   env = {}
   package.loaded[name] = env
 end
 env._NAME = name
 env._M = env
 for _, f in ipairs{...} do
   env = f(env) -- <=== allow f to redefine env
 end
 return env
end

local lua_libs = {}
for k,v in pairs(package.loaded._G) do
 lua_libs[k] = v
end

function package.seebase(mod)
   local env = {}
   setmetatable(env, {
      __index = function(t,k)
         return rawget(mod, k) or rawget(lua_libs, k)
      end,
      __newindex = mod
   })
   return env
end
----------

This proposed package.seebase exposes Lua standard libraries to the
module without exporting them. (I only had to make one slight change
to the module() function you posted; if that is doable without this
change I'd be happy to be corrected.) I think package.seebase brings
the benefits of package.seeall without its two big drawbacks mentioned
above.

I'd even argue that this should be the default behavior for module()
when called with a single argument, in line with David Manura's
concerns that the canonical "easy way" should help the user get things
right.

> Moreover,
> a modified 'load' function forces everyone to live with its magic.

Not necessarily; Fabio's original loader did this but loader5
restricted the magic to the users of module().

-- Hisham
http://hisham.hm/ - http://luarocks.org/