lua-users home
lua-l archive

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


DC wrote:
> Thanks for the env example.  After looking through the code I'm still
> unclear how these new environments for c functions and user data is
> helpful getting GC on Lua objects.

Create userdata as usual and associate it with your C object (put
a boxed pointer into the userdata or use the userdata space for
storing the contents). With 5.1w5 you can associate any Lua object
with a userdata object by storing it in the userdata environment.
This is nothing more than a single tagged value slot in the internal
structure of the userdata object.

If you want to store multiple Lua objects (like in my example)
then store a table in the userdata environment and put your Lua
objects into this table.

When the userdata object gets GC'ed, the Lua object in the userdata
environment gets GC'ed, too (unless there are still references to
this object of course).

Mark Hamburg wrote:
> With regard to Mike's example, I'm curious about whether there is guidance
> for when I should choose to use an upvalue for a C function and when I
> should choose to use an environment.

The C function environment is conceptually the same thing as an
additional upvalue. At least that's how it's implemented. But there
are a few differences:

- It's always present -- not using it would waste space. So if you
  are thinking of creating the same upvalue for a bunch of functions
  (e.g. a module), you definitely want to use C function environments.
  You can find an example of this conversion by diffing liolib.c from
  5.1w4 vs. 5.1w5.

- New functions created by a running C function inherit the
  environment. This is convenient for modules where you want all
  dynamically instantiated functions (e.g. iterators) to have access
  to a common environment. With upvalues you have to manage inheritance
  on your own.

- New userdata created by a running C function inherits the
  environment, too. This may or may not be what you want. You can
  easily override this behaviour with a call to lua_setfenv().

In my "queue" module example all C functions get the metatable as
the environment. This allows for a fast check whether the functions
are called with the proper metatable (queue_udata()).
[This is ~35% faster than luaL_checkudata() and could be made even
faster with an additional lua_metaequal() API function.]

The userdata objects created by the queue module are containers.
So each one of them gets a new table as the environment which is
used to store the Lua objects put into the container.

Other modules using userdata objects may have different requirements
and uses for the userdata environment (e.g. chain pointer, double
dispatch, real object behind a proxy object ...). You definitely
want to convert all code that uses weak tables to map userdata
objects to associated Lua objects.

Some very simple userdata objects may have no use for the userdata
environment. Yes, this wastes a little bit of space. Here are the
old and the new sizes of the constant portion of userdata objects:
32 bit CPUs: 16 -> 20 bytes, 64 bit CPUs: 32 -> 40 bytes
(this may or may not make a difference, depending on your malloc()
implementation). But I think the advantages outweigh this disadvantage.