[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua addition proposal: Userdata as function environment
- From: Rici Lake <lua@...>
- Date: Wed, 4 Oct 2006 15:24:53 -0500
On 4-Oct-06, at 3:02 PM, Jerome Vuarand wrote:
While trying to answer some recent mails on the list I did some
experiment with environments and noticed that it is not possible to set
anything else than a table as a function environment.
I think it would be nice to be able to set any value as the
environment,
especially a userdata. The value in question should have __index and
__newindex metamethods. If it don't variable reads would return nil and
variable writes would be ignored.
An example of use would be a configuration mechanism similar to one
that
has been discussed recently. Here a C++/Lua hypothetical example:
Why not just use an empty table whose __index and __newindex methods
use the userdata? In effect, they could be the same __index and
__newindex metamethods you would use with the userdata.
The following hardly changes your example at all:
(Note: I'm using lightuserdata here, something I would normally never
do, but you don't seem to be attaching a __gc metamethod to your
userdata so I'm assuming that you are prepared to manage them as
resources without assistance from the Lua garbage collector).
So: here we create the proxy environment table and its metatable,
attaching the configuration object as an upvalue to both getter and
setter:
static int pushobject(lua_State* L, Object* object)
{
// Put object address as a userdata
lua_pushlightuserdata(L, (void *)object*);
// Create the environment table
lua_newtable(L);
// Create the metatable
lua_newtable(L);
lua_pushvalue(L, -3); /* Copy of l.u.d */
lua_pushcclosure(L, config_setvar, 1);
lua_setfield(L, -2, "__newindex");
lua_pushvalue(L, -3); /* Copy of l.u.d */
lua_pushcclosure(L, config_getchild, 1);
lua_setfield(L, -2, "__index");
lua_setmetatable(L, -2);
return 1;
}
Now, a slight modification to the getter and setter is all it takes:
// Get a child, will be called as __index
static int config_getchild(lua_State* L)
{
// Small change to next line ********
Object** pconfig = lua_touserdata(L, lua_upvalueindex(1));
Object* child = (*pconfig)->getchild(lua_tostring(L, 2));
if (child)
return pushobject(L, child);
else
return 0;
}
The same change needs to be made to the first line of config_setvar.