lua-users home
lua-l archive

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


On Thu, Jun 19, 2014 at 03:54:56PM -0700, Josh Haberman wrote:
> On Thu, Jun 19, 2014 at 2:26 PM, Aaron Faanes <dafrito@gmail.com> wrote:
> > The safest solution IMO would be to write your luaopen_*
> > to be resilient (or a no-op) in the face of redundant requires.
> > If all they do are assignments to the global environment,
> > this level of safety is easy to attain. I'd be curious to hear
> > if this wasn't the case for you. :)
> 
> My C module keeps a weak table mapping (C pointer) -> (Lua wrapper).
> This table is created in my luaopen function. So if my luaopen
> function got called more than once, I would end up with more than one
> table. That would be bad because I generally rely on the guarantee
> that I have at most one Lua wrapper per C object.
> 
> I currently store this table in the registry, so I do have the option
> of checking to see whether the table already exists when I create it.
> But I think I should be able to store this as an upvalue of my C
> functions instead if I choose (for example, if it gives better
> performance). If I store the table as an upvalue (the equivalent of
> declaring it as "local" in a pure Lua module), there would be no way
> to do the right thing if my luaopen function gets called multiple
> times.
> 
> > I guess I treat require's "load only once" ultimately as a very
> > strong hint rather than as a fundamental guarantee - it's just
> > too easy for the programmer to break.
> 
> It seems like an important guarantee if the module has any state.

There's nothing preventing a user from directly calling loadfile on a Lua
module, either.

Let's backtrack to your circular dependency problem. How could it come to
pass that a _user_ could create a circular dependency between two of _your_
own modules? That would be an exceptionally odd and circumstance, and if
even possible likely quite contrived.

Given that you're aware of the luaL_requiref issue, and it can really only
arise because of code you wrote yourself, it's simple enough to solve it by
writing a luaL_requiref wrapper, such as:

static void my_requiref(lua_State *L, const char *modname,
  lua_CFunction openf, int glb)
{
  luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
  lua_getfield(L, -1, modname);
  lua_remove(L, -2);

  if (lua_isnil(L, -1)) {
    lua_pop(L, 1);
    luaL_requiref(L, modname, openf, glb);
  }
}