lua-users home
lua-l archive

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


First of all. You have already defined some USEFUL userdata and some OTHERUSEFUL userdata. Each one has a list of functions defined in C.

I will assume that OTHERUSEFUL will inherit from USEFUL. To do that, Lua uses metatables.

In C code, one should do the following:

<OTHERUSEFUL C-code>

void *otheruseful_instance = lua_newuserdata(L, sizeof(void));
lua_newtable(L);
luaL_setmetatable(L, "USEFUL"); // inheritance starts HERE
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index"); // necessary

// add functions specific for OTHERUSEFUL
// DO NOT forget to add
lua_pushcclosure(L, &asstring, 0);
lua_setfield(L, -2, "__tostring");
lua_pushcclosure(L, &gcollect, 0);
lua_setfield(L, -2, "__gc");
// optionally
lua_pushliteral(L, "OTHERUSEFUL");
lua_setfield(L, -2, "__name");

...

lua_setmetatable(L, -2); inheritance ends HERE

...

< END >

However, if you apply the function luaL_checkudata, you still have the problem of incompatibility with the functions inherited by OTHERUSEFUL from USEFUL.

To solve this problem, I added the following function to USEFUL or anywhere it might be required (a userdata that will be inherited from).

< C-code>
// replace every use of luaL_checkudata by myL_checkudata.

int checkmetatable(lua_State *L) {
    if (lua_getmetatable(L, -2) {
        lua_replace(L, -3);
        if (lua_rawequal(L, -1, -2))
            return 1;
    }
    return 0;
}

void *myL_testudata(lua_State *L, int ud, const char *tname) {
    void *p = lua_touserdata(L, ud);
    if (p != NULL) {
        if (lua_getmetatable(L, ud)) {
            luaL_getmetatable(L, tname);
            if (!(lua_rawequal(L, -1, -2) || checkmetatable(L)))
                p = NULL;
            lua_pop(L, 2);
            return p;
        }
    }
    return NULL;
}

void *myL_checkudata(lua_State *L, int ud, const char *tname) {
    void *p = myL_testudata(L, ud, tname);
    if (p == NULL) { // value is not  a userdata with a metatable
        // error signal
    }
    return p;
}

< END >

If it looks cryptic just take a look at "luaxlib.c"; you will find how the original functions were written.

Cheers,

// Carlos












El vie., 22 de may. de 2020 a la(s) 18:45, Carlos Aguilar (capagp@gmail.com) escribió:
If I am getting it right you are facing an inheritance issue.

I had a similar situation a while ago. And as suggested by others, I implemented an inheritance mechanism over userdata to solve it.

Let me share my solution.

// Carlos



El vie., 22 de mayo de 2020 17:35, Laurent FAILLIE <l_faillie@yahoo.com> escribió:
Hello,

I'm working to a graphical framework in C dealing with Cairo graphics.

I'm creating an object named SelDCSurface that deals with Cairo's surface

Some methods are attached to it using luaL_setfuncs() or luaL_register().

Now, I'm working on SelDCImageSurface which is basically an extension of SelDCSurface : it has to know all methods of SelDCSurface plus its own.

1/ How to do that ?
I guess I can use luaL_setfuncs() or luaL_register() more than once on the same object, to add additional methods, isn't it ?

2/ my main concern is the function used if "self" object has the right type

I.E. for method

mySelDCSurface:GetSize()

the C code is

----------
static struct SelDCSurface *checkSelDCSurface(lua_State *L, int where){
    void *r = luaL_checkudata(L, where, "SelDCSurface");
    luaL_argcheck(L, r != NULL, where, "'SelDCSurface' expected");
    return (struct SelDCSurface *)r;
}

static int GetSize(lua_State *L){
    /* Return surface's size
     * <- width, hight
     */
    struct SelDCSurface *srf = checkSelDCSurface(L, 1);

    lua_pushnumber(L, srf->w);
    lua_pushnumber(L, srf->h);
    return 2;
}
---


The problem, is when called from a SelDCImageSurface object, GetSize() will still call checkSelDCSurface() which fails as facing a "SelDCImageSurface" and not a "SelDCSurface".

Any smart way to avoid that ?

Thanks

Laurent