lua-users home
lua-l archive

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

Josh Haberman wrote:
> From my reading of ltable.c and lvm.c it appears that Lua does not
> remove table entries when a program does t[x] = nil, but just sets the
> entry's value to nil.  Please correct me if I'm wrong.
> Is there a reason for this?

1. To allow deletion of values during a table traversal.

   If the key was removed, too, the traversal would lose its
   anchor. This is because traversals in Lua are incremental,
   based on the previous key, and don't need extra context
   (e.g. a hash table position).

   [LuaJIT tries to use a hidden context to speed up traversals.]

2. To preserve the key slot in the table.

   Fields that toggle from non-nil to nil and back do not need to
   create a new key in the table every time. Creating a new key is
   substantially more expensive than re-using an existing key slot.

3. To save work.

   Removing individual keys is expensive, because you'll need to
   traverse the whole chain for each key. This work is wasted in
   case the table is subsequently dropped or needs to be grown. In
   the latter case the table is scanned and copied, anyway. The
   slots with nil values can simply be ignored.

Note that there are some subtle consequences for garbage
collection, too. That's why e.g. Lua 5.1/5.2 uses LUA_TDEADKEY to
replace dead keys for collectable objects during a GC cycle.

LuaJIT uses a different strategy and doesn't need the quirky
LUA_TDEADKEY workaround. That saves some work during GC and has
the nice side-effect of preserving the key slot in the table, even
across GC cycles, unless the key itself is collected (which means
there's no need to preserve the slot).

Performance hint: If you need to toggle values in tables between
on/off states, try to avoid using 'nil' as the off state. It's
better to use e.g. 'false', which a) definitely preserves the key
slot and b) avoids an extra __newindex metamethod check for each
off->on transition.