30
  • What is userdata and lightuserdata in Lua?
  • Where do I need it?

I have been trying to wrap my head around it for some time now, but I can't seem to find any tutorials/explanations that I really understand.

Why do you need them, why can't you just directly bind C functions to Lua metatables?

Lars
  • 301
  • 1
  • 3
  • 3

4 Answers4

59

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.

RBerteig
  • 41,948
  • 7
  • 88
  • 128
7

Well, userdata is data from the C-side that can be used from within Lua. Such as for example file handles as io.input are userdata (try print(type(io.input))). You'll need it yourself if you start messing about with the Lua C-API (or use the newproxy function, which gives you an empty userdatum, upon which you can set a metatable (see Hidden Features http://lua-users.org/wiki/HiddenFeatures) on the Lua-users wiki).

A good introduction is: http://www.lua.org/pil/28.html

As for the C functions stuff: yea you can just register C functions as functions to be called from within Lua, but it won't get you other data types, pointers to data on the C side, etc etc.

jpjacobs
  • 9,359
  • 36
  • 45
4

First, userdata means full userdata. Here are two solutions to implement CharArray. Please see below:

//full userdata 
extern "C" int newarray(lua_State* L)
{
     int n = luaL_checkint(L, 1);
     size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
     CharArray* a = (CharArray*)lua_newuserdata(L, nbytes);
     a->size = n;
     return 1;
}

//light userdata 
extern "C" int newlarray(lua_State* L)
{
    int n = luaL_checkint(L, 1);
    size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
    CharArray* a = (CharArray*)(new char(nbytes));

    lua_pushlightuserdata(L,a);
    a->size = n;

    return 1;
}

Full userdata is a raw memory area with no predefined operations which offers from Lua. So userdata must be managed by the garbage collector. In the other hand, light userdata is just a value that represents a C pointer (that is, a void * value). Light userdata do not need to be managed by the garbage collector (and are not).

chlin
  • 41
  • 4
3

you can use userdata Whenever you have some amount of data that you want do be managed by the lua gc. For example you could use it for C++ objects. Some examples for c++-objects with userdata: You could save one in userdata then you can forget about it in C++ as it will be managed by lua. So you could reference it in luavariables and pass it to functions that call a memberfunction of the c++ object. (there are ways to generalize that of course like putting a generic function object in the userdata, bind that as upvalue to a C-closure and register that c-closure on a luaobject that represents the lua-side of the c++ object, that involves userdata as well). If you don't want the lua gc to manager your objects and just want to reference your c++ object from lua you can store a pointer to it as light userdata.

DaVinci
  • 1,391
  • 2
  • 12
  • 27