tags:

views:

73

answers:

2

I have some classes in C++ that I would like to expose to Lua. I can call Widget:New() to get return userdata with a metatable set to the table WidgetMeta. WidgetMeta has all the C++ functions in it, and it's __index is set to itself, so I can do this:

w = Widget:New()
w:Foo() -- Foo is defined in C code

That's all pretty straightforward.

Now here's the part I can't figure out. I want to be able to put Lua defined variables and functions on my userdata as if it was a table. This can't be done directly obviously. I can't drop it on the userdata, because I want it to be unique per userdata.

w1 = Widget:New()
w2 = Widget:New()

function w1:Bar() print "Hello!" end -- Both functions unique
function w1:Baz() print "World!" end -- to their own userdata

My current plan of attack is to have the metatable have a special table on it that maps between userdata and table where I can store per-userdata functions and variables. The problem is that I'm not sure what the best way to go about doing that is, or if there's a better solution. so my question is twofold: When I set up my __index and __newindex metamethods, do I write them in Lua code in a text file and run it before I run the rest of the stuff, or do I put the Lua code directly from a C string in my program via luaL_loadstring, or do I do it with the C interface and deal with all the stack manipulations? and second, how do I write that function... but I'll deal with that once I decide which is the best route to take.

+3  A: 

Add a function environment to the userdata, and redirect access through that.

Here's some old code of mine that describes the process.

static int l_irc_index( lua_State* L )
{
    /* object, key */
    /* first check the environment */ 
    lua_getfenv( L, -2 );
    lua_pushvalue( L, -2 );
    lua_rawget( L, -2 );
    if( lua_isnoneornil( L, -1 ) == 0 )
    {
        return 1;
    }

    lua_pop( L, 2 );

    /* second check the metatable */    
    lua_getmetatable( L, -2 );
    lua_pushvalue( L, -2 );
    lua_rawget( L, -2 );

    /* nil or otherwise, we return here */
    return 1;
}

static int l_irc_newindex( lua_State* L )
{
    /* object, key, value */

    lua_getfenv( L, -3 );
    lua_pushvalue( L, -3 );
    lua_pushvalue( L, -3 );
    lua_rawset( L, -3 );

    return 0;
}
jsimmons
Thanks, this was much cleaner than was I was going to try to do :D
Alex
A: 

You should really take a look at tolua++, which has a very similar concept. All the userdata objects created from lua have a hidden table to store their properties.

This section of the manual describes it : http://www.codenix.com/~tolua/tolua++.html#additional