1

I want to create a global interface for a struct instance accessible in Lua. For example, I would create a global instance of a metatable called window as main_window, I would want to then do things like this from Lua:

main_window.color = {1, 2, 3}
main_window.position.x = 64
main_window.show(true)

In an attempt to do this, I used the code from this answer as a base since it's the closest thing I could find. I ended up with an API like this

lua_create_window_type(L);
lua_expose_window(L, main_window);
lua_setglobal(L, "main_window");

...

static int lua_window_index(lua_State* L)
{ 
    struct window_state** w = luaL_checkudata(L, 1, "window");
    char* index = luaL_checkstring(L, 2);
    if (strcmp(index, "x") == 0) {
        lua_pushnumber(L, (*w)->x);
    } else if (strcmp(index, "show") == 0) {
        lua_pushcfunction(L, lua_window_show);
    } else {
        ...
    }
    return 1; 
}

static int lua_window_newindex(lua_State* L)
{
    struct window_state** w = luaL_checkudata(L, 1, "window");
    char* index = luaL_checkstring(L, 2);
    if (strcmp(index, "x") == 0) {
        (*w)->x = luaL_checkinteger(L, 3);
    } else {
        ...
    }
    return 0;
}

I am inevitably going to end up with tens or hundreds of functions and variables I want to be accessible. Using this template I would have to manually create a if strcmp == 0 else if for every single one. I'd have to duplicate the entire block to allow assignment. I also don't want to end up with functions near the end being comparatively slow to call due to the amount of string comparisons. Overall this does not seem like a "maintainable" solution, nor one the Lua authors would have intended.

When I only needed functions all I had to do was push a standard global table and whatever functions I needed, but trying to allow direct variable access like a native Lua table makes this more difficult (before you ask why not just use functions, I've tried and only having "getter/setter" function access from Lua is very painful and ugly for my uses).

Suggestions for more maintainable alternatives to duplicated if/else blocks?

Accumulator
  • 873
  • 1
  • 13
  • 34
  • 2
    "*I am inevitably going to end up with tens or hundreds of functions and variables I want to be accessible.*" Given this, are you *really* sure you want this to be a C struct, rather than just a Lua table? – Nicol Bolas Sep 20 '18 at 21:05
  • A hash table would be great, for performance, readability, and maintainability. Anyway, it might be that rethinking the entire approach might be cleverer than that. But if you want to do it like this, a hash table is definitely a good choice. – cadaniluk Sep 20 '18 at 21:07
  • "Given this, are you really sure you want this to be a C struct, rather than just a Lua table?" Yes, I'm exposing native C functionality, not something that can at all be done with pure Lua. – Accumulator Sep 20 '18 at 21:28
  • 1
    You could make a Lua table (to act as a hashmap in C), but don't expose this Lua table to Lua script. – Egor Skriptunoff Sep 21 '18 at 09:48
  • Start out with getter and setter functions, and then add a newindex handler that for a given name "X" looks up and calls the method "set_X". Same thing for the index handler, but you have to handle regular method accesses there as well. There are some optimizations possible (e.g. avoiding the "set_" + "X" string concatenation on every access), but that's the gist of it. – siffiejoe Sep 25 '18 at 06:46

0 Answers0