lua-users home
lua-l archive

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

Going down this path, what might actually be nice is to have the modifiers (e.g.,package.seeall) take and return both an environment and a module. They start out equal but they can move apart. So, package.seeall builds an environment table that or's together the module and the environment in place before the call to module and sets it to write into the module table. package.writeprotect could replace the module with a proxy table referencing the module table rewiring _M appropriately. But note that those functions need to be specified in the executed order, so maybe this should all just be standard behavior.

	function makemodule( name, oldenv, writeprotect )

		-- yada, yada look for an existing module, etc

		local M = { }
		local ENV = M
		local MM = M

		if writeprotect then
			MM = setmetatable( { }, {
				__index = M,
				__newindex = function( _, k, v )
					error( string.format( "Attempt to write field %s of module %s", tostring( k ), tostring( name ) ) -- level #?
			} )

		M._M = MM
		-- set M._NAME and M._PACKAGE as appropriate

		if oldenv then
			ENV = setmetatable( { }, {
				__index = function( _, k )
					local v = M[ k ]
					if v == nil then	-- Don't ignore v == false
						v = oldenv[ k ]
					return v
				__newindex = M -- Does this need to take extra care about what happens if we set the field to nil?
			} )

		package.loaded[ name ] = MM

		return ENV, M


5.2 could use this as:

	_ENV = makemodule( name, _ENV, writeprotect )

5.1 would presumably want to wrap it with code that fetched the environment. 5.2 could do this too though actually 5.2 makes it easier to work with the environment.

One distinct downside from a performance standpoint, however, is that global lookups get expensive because they need to fail in the proxy and then invoke the metamethod code. So, I still don't know that I see the value in fiddling with the environment.