A userdata is a garbage-collected value of an arbitrary size and content. You create one from the C API, with lua_newuserdata()
, which creates and pushes it on the stack and gives you a pointer to its content to initialize as you see fit from C.
It is very comparable to calling malloc()
. A key distinction from malloc()
is that you never need to call free()
, rather you just allow the last reference to it to evaporate and the garbage collector will reclaim its storage eventually.
They are most useful for holding data that is useful from C, but which must be managed from Lua. They support individual metatables, which are the key feature that allows binding C or C++ objects to Lua. You simply populate its metatable with methods written in C that access, modify, and/or use the content of the userdata, and the result is an object that is accessible from Lua. A good example of this is the io
library, which stores C FILE *
pointers in userdata, and provides bindings that implement the familiar read
, write
and similar methods. By implementing an __gc
metamethod, the io
library makes sure that one of its file
objects closes the associated FILE *
when it is collected.
A light userdata is how you represent a pointer to something as a value in Lua. You create one by calling lua_pushlightuserdata()
with the pointer that is its value. They are managed by Lua much the same way that a number is. They are useful when you need to name a C object in a way that the name can be passed around within Lua, but the object's lifetime is not managed by Lua. Like numbers are equal when they have the same value, light userdata compare equal when they hold the same pointer. Like numbers, they exist as long as they are on the stack or stored in a variable, and they do not have individual metatables and they are not garbage collected.