lua-users home
lua-l archive

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


Hi all!

[Warning: long post ahead]

I realized the discussion on the originating thread was hitting the limits of my Lua knowledge, so I'm starting a new thread to avoid adding noise to it with "newbie stuff".

All the discussions about environments, globals and modules have confused me a bit (especially after rereading what's in the WIKI about it). Therefore I'd like to receive comments on my current practice when it comes to write a new module (nothing original below, just a concoction of what I read and learned about modules from the list and WIKI in the last months).

What I'm trying to assess here is whether the following approach (very basic, avoiding as much "magic" and "debug" library support as possible) is reasonably foolproof and safe.

Note that it is a rather "verbose" solution, and that's an intended trade-off for (hopefully) better encapsulation, less "baggage", and good performance (thanks to heavy use of locals), all under an "avoid globals like The Plague" approach.

Are there pitfalls/caveats in this approach (under the assumption that the debug library is not used to tamper with the "module system")? If every module in the system had this structure, would I be safe from side effects from other modules/components/scripts (directly or indirectly loaded, either with "require" or with "loadXXX" functions)? Am I missing something or assuming too much?

Any comments appreciated!

TIA
--- Lorenzo



Currently my modules have the following structure (Lua 5.1.4 assumed):


-- mymodule.lua (placed in directory a\b\c on Lua's search path)

-- if needed to locate other components:
local module_dir = debug.getinfo(1, "S").source:match[[^@[^\/]-$]] and "." or debug.getinfo(1, "S").source:match[[^@?(.*)[\/][^\/]-$]]

local print = print
local setfenv = setfenv
local setmetatable = setmetatable
local table_concat = table.concat
-- ... other "localization" of needed standard globals


local M_ENV = {} -- just a sink for unintended global accesses, not used internally
setfenv(1, M_ENV)
local M = {}	-- module table (will be "exported" to outer world)

-- "requiring" of external modules goes here:
local extmod = require "org.lua.morecoolstuff"

-- example of private data and function:
local x = 12
local function helper() --[[ do stuff ]] end


-- example of function to be exported:
local function M_MyCoolFunc(a,b,c)
 --[[ do stuff ]]
end
-- "declare" M_MyCoolFunc to be exported
M.MyCoolFunc = M_MyCoolFunc


-- instead of simply "return M", so what gets
-- into "package.loaded" is read-only:

return setmetatable({}, { __index = M, __metatable = "locked",
  __newindex = function()
    error "attempt to write to read-only table"
  end })
-- end mymodule.lua

-- module usage:

local mymod = require "a.b.c.mymodule" --> module's "namespace" table

mymod.MyCoolFunc("Hep!", 1, 2)