lua-users home
lua-l archive

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




On Tue, Sep 16, 2014 at 11:43 AM, Philipp Janda <siffiejoe@gmx.net> wrote:
Am 16.09.2014 um 15:58 schröbte Andrew Starks:
On Tue, Sep 16, 2014 at 7:42 AM, Dirk Schippers <lua@frixx-it.com> wrote:

I don't like the Lua registry (especially because of the keys that should
be carefully chosen to not mess things up - I use a lightuserdata adressed
to some static C variable as key - ), but I think I needed it for this.

That's a reasonable way to do it (and a perfect example of where to use lightuserdata).

[...] 5.1 doesn't have `uservalue`s.

They are called "environments" in Lua 5.1. And that's what I would recommend (instead of a per-instance metatable which doesn't work with lightuserdata anyway). There is a storage hierarchy in Lua where you can store stuff:

1) Lua state local: registry (private) or globals table (public)
2) module local: function upvalues (private)
3) (userdata-)type local: metatable (public or private)
4) (userdata-)instance local: environment/uservalue (private)

Nothing prevents you from using a per-instance metatable, but there are some things in Lua that work better with a per-type metatable (e.g. some relational operators, and `luaL_checkudata` etc.). And of course you can always go one level higher by using a table with suitable keys ...

Now about those lightuserdata: I know "lightuserdata" sounds much nicer and "lighter" than full userdata, but in 90% you want full userdata. Lightuserdata are only useful/safe under very special circumstances. If used outside of those cases, they have the following problems:

1) You have to implement your own type checking (i.e. `luaL_checkudata` won't work for you). Lua can't distinguish between lightuserdata except by pointer value, so your functions must be able to determine that a lightuserdata really belongs to you by looking at the pointer value alone.
2) Lua doesn't manage the lifetime of the data pointed to by lightuserdata. That means that you can have lightuserdata to memory that's long gone, or memory that's already inaccessible by Lua (and you have no way of knowing about that).
3) Lightuserdata don't have environments/uservalues.
4) All lightuserdata share a single metatable. If you want to use more than one module which sets a metatable on lightuserdata, you are screwed. (Btw., that also means that all your windows will share the same `OnMouseMove` function!)


HTH,
Philipp





I think that the important difference is that Lua allocates userdata, returning a pointer that it allocates: `void * lua_newuserdata (lua_State *L, size_t size);` You can't stash this pointer in a C struct and then call into Lua and then later retrieve it, once the C `L*` goes out of scope.

With lightuserdata, you give the pointer to it: `void lua_pushlightuserdata (lua_State *L, void *p);` In this use case, that's important, because you need to find the C object (Window handle) inside of Lua. You can't do that with userdata, unless you want to manually do that using some other kind of uuid magic.

And so, one is not better than the other. They're used for different things. 

If you want an object-like structure that you use in Lua and manage in C, userdata is your best friend and you can't use lightuserdata as a substitute. If you'd rather do everything in Lua, you can use a little bit of userdata and make the object in Lua, or use no userdata and just use the language and callbacks to do the same work. 

If I understand the world correctly...

-Andrew