lua-users home
lua-l archive

Re: Lua C API : How to have an "object" deriving form another one.

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


Hi Carlos,

thanks for your code.
If I understand well, the first part of the code copy the meta from the initial "USEFUL" to the newly created "OTHERUSEFUL", right ?

But I don't understand the code of myL_checkudata().
I mean, when you call it, you have specify table's name

...

static int myFuncPartOfUseful(lua_state *L){
data = "">myL_checkudata(L, 1, "USEFUL");
}

but when called from MYOTHERUSEFUL ... how will it detect it the name to check is now MYOTHERUSEFUL and not USEFUL ?

Le samedi 23 mai 2020 à 03:00:47 UTC+2, Carlos Aguilar <capagp@gmail.com> a écrit :


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

AltStyle によって変換されたページ (->オリジナル) /