|
On Aug 10, 2009, at 12:18 AM, Joshua Haberman wrote:
Alex Davies <alex.mania <at> iinet.net.au> writes:I had the same problem when I was just starting out, as it isn't obvious in the documentation but Lua allows a table to be associated with a userdataand marks it appropriately. So all circularly references are handled correctly, something that's hard to do via the registry. Quick example: lua_newuserdata(L, 0); lua_newtable(L); lua_pushvalue(L, -1); lua_setfenv(L, -3);Thanks for the info Alex! It's true that this is better than putting stuff in the registry. I would still prefer to avoid having to construct this per-userdata table at all, but this at least makes it a little more tolerable.
Note that from a space standpoint, if you use the array portion of the table, the overhead is relatively small. It's basically the cost of having a table object allocated and whatever per allocation overhead your memory allocator imposes.
From a usage standpoint, it's a bit of a pain since one needs to fetch the table in any functions that work on the data, though that's not horrendous. (I have thought about adding a pseudo-index for the environment table of the value at index 1 in the stack frame just to make working with userdata objects with environment tables easier. Doing so is pretty easy. Doing so and keeping compatibility with any code that has expectations about what range the pseudo-indices occupy is risky.)
From a performance standpoint, the hit comes in having to go through lua_rawgeti and lua_rawseti and then having to process and pop the results. That's more or less the price for having a compact API to Lua that completely shields implementation details such as the TValue structure. (Consider, for example, that LuaJIT 2 does not use this representation for Lua values.) At the expense of a larger API, it could be useful to provide more combined accessors -- e.g., lua_rawgeti_number -- though note that the character pointers for strings technically only remain valid as long as the string is on the stack.
Mark