lua-users home
lua-l archive

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


On Fri 31/Dec/2010, Hans van der Meer wrote:
> This is a program completely doen by myself. For the curious: it
> implements the same API as the standard io-module, but can dynamically
> choose between various backends, e.g. reading/writing compressed, to a
> memory file,etc.

Since Lua is a dynamically typed language, you need only create objects
with the same methods as Lua's file objects, and you can pass them to
functions that expect a file object. (This approach is known as duck
typing.)

N.B. There is no need to re-implement the standard file objects that Lua
provides.

> I kept the filehandle userdata at hand with
> 	lua_pushlightuserdata(L, p); /* p = my filehandle userdata */
> 	lua_rawseti(L, LUA_ENVIRONINDEX, stdindex); /* register in environment */

Don't use a lightuserdata for anything you give to Lua code. Use a full
userdata, which can be properly finalised and garbage-collected.

> and also to make stderr globally available by this code in the C-module:
> 	lua_pushlightuserdata(L, p); /* p = my filehandle userdata */
> 	lua_setglobal(L, "stdin"); /* register global under its name */
> 
> I verified that the top of the stack has my filehandle before the rawset and setglobal.
> But neither 'io.stderr:write' nor 'stderr:write' have a known stderr.
> 
> Could it be that I misunderstand the effect of the setglobal?

lua_setglobal(L, "stdin"); will store your userdata as the global
variable "stdin".

However, lightuserdatas don't have metatables, so any
functions you call with this lightuserdata won't know that it's of the
correct type. This is important if you value Lua's safety. You wouldn't
want a crash or worse, caused by some Lua code passing invalid
arguments.

Instead, you should use full userdatas, and create a table to use as the
metatable. This metatable is attached to the userdatas and used to
identify its type.  Since Lua code can't change the metatable of a
userdata (without the dangerous debug module or similar), your C
function can be sure that, if the metatable is correct, the userdata is
of the correct type.

The metatable also defines what operators and methods are available for
the userdata. (See the __index metamethod.)

You should attach the metatable to new (full) userdatas that you create.
You can store the metatable in the registry table (see
luaL_newmetatable, luaL_getmetatable, luaL_setmetatable (5.2 only)), so
you know where to find it when you need to attach it to a userdata.

Another technique is to set the __index metatable entry to point to the
module table. This way, functions that take your userdata as their first
parameter can be put in only one table, and used in two ways:
  modulename.method(obj)
  obj:method()