[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: A guide to building Lua modules
- From: Philipp Janda <siffiejoe@...>
- Date: Mon, 14 Apr 2014 13:54:54 +0200
Am 14.04.2014 11:03 schröbte Enrique Garcia Cota:
Hi there,
Hi!
I've written a series of articles about building Lua modules - it's here:
http://kiki.to/blog/2014/03/30/a-guide-to-building-lua-modules/
I would appreciate any feedback or comments on it.
Rule #1 (Do what Lua does):
One thing Lua does is "provide mechanism not policy"[1]. Yet you are
recommending that other people follow your rules. As of your rule #5 you
must have good reasons for this, and I'd be very interested in
discussing those with you.
[1]: http://lua-users.org/wiki/MechanismNotPolicy
Rule #3 (Allow monkeypatching):
Lua being a dynamic language doesn't mean that you should monkey-patch
(or allow monkey-patching). Lua also is a language that allows you to
prevent monkey-patching for certain modules, so it basically comes down
to "Allow monkey-patching because I like monkey-patching" which by your
own definition isn't a good reason.
Regarding the "Beware of locals" part: I think it all depends on the
public interface of your module (whether implicit or documented
explicitly). In your example I would assume from the function names that
`add` adds, and `mult` multiplies. Nothing suggests that monkey-patching
`add` should change the behavior of `mult`. This is also exactly "what
Lua does", e.g. `table.insert` uses `rawget` and `rawset` internally
(well, `lua_rawget` and `lua_rawset`, but the principle is the same). Do
you expect `table.insert` to change its behavior if you monkey-patch
`rawget`? `print` on the other hand is documented to call `tostring` on
its arguments, so you can expect `print` to change its behavior if you
redefine `tostring`.
In most cases I consider the use of standard library functions in my
modules to be an implementation detail, so by caching them in locals I
_enable_ you to monkey-patch to your heart's desire without fear of
breaking the functions of my modules. And by monkey-patching you usually
want to make writing code more convenient. My modules can't profit from
that because they are already written ... and tested in a certain
environment ... and unaware of your enhancements.
And btw.: locals are faster than upvalues, so for tight loops it might
make sense to cache the upvalues defined at the beginning of the module
in locals ... :-p
Rule #5 (Beware of multiple files):
If you move your modules from `./my-package` to `./lib/my-package`, you
should change `package.path` and not your module references!
And your `current_folder` trick is (slightly) broken. When you run
`my-package/init.lua` via `require( "my-package" )` `...` will contain
"my-package", not "my-package.init", so you must not remove the last
module component in this case. If you call `require( "my-package.init"
)` however, the extra ".init" is there and must be removed to figure out
the package name. You can fix that by explicitly testing for ".init" at
the end of the module name.
If you don't use `my-package/init.lua` at all but `my-package.lua`
instead, things get much easier: You just use `local mod1 = require(
(...)..".module1" )` to get to your submodules. (Again this only matters
when you incorporate your module into a larger module hierarchy -- other
location changes can be handled with an update to `package.path`.)
Thanks and best regards,
Enrique ( kikito / @otikik )
Philipp