Lua: Querying the name of the metatable of a userdata object

I want to query the name of the metatable of some object.

Consider that I have some metatable registered as the following:

Object obj; // some C object

luaL_newmetatable(lua, "my_metatable"); // it's empty

lua_pushlightuserdata(lua, &obj);
luaL_setmetatable(lua, "my_metatable");
lua_setglobal(lua, "obj_");

The documentation here states tha luaL_newmetatable does dual association, i.e. It uses the name as a key to the table and the table as a key to the name. So, with this knowledge, I thought I can achieve my goal as the following:

int getMTName(lua_State *L)
{
    lua_getmetatable(L, 1); // get the metatable of the object
    lua_rawget(L, LUA_REGISTRYINDEX); // since the metatable is a key
                                      // to its name in registry, use 
                                      // it for querying the name
    return 1; // the bottom of the stack is now the name of metatable
}

and registered it like:

lua_pushcfunction(lua, getMTName);
lua_setglobal(lua, "getMTName");

But, unfortunately, it didn't work, it returned nil. So, what's my bad?

Here, some full source code (in C++):

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#include <iostream>

struct Object {
    int x;
};

int getMTName(lua_State *L)
{
    lua_getmetatable(L, 1);
    lua_rawget(L, LUA_REGISTRYINDEX);
    return 1;
}

int main(int argc, char **argv)
{

    lua_State *L =luaL_newstate();
    luaL_openlibs(L);

    Object obj;

    lua_pushcfunction(L, getMTName);
    lua_setglobal(L, "getMTName");

    luaL_newmetatable(L, "my_metatable");

    lua_pushlightuserdata(L, &obj);
    luaL_setmetatable(L, "my_metatable");
    lua_setglobal(L, "obj_");

    int e = luaL_dostring(L, "print(getMTName(obj_))");

    if (e)
    {
        std::cerr << "ERR: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);
    }

    return 0;

}

Output is nil. My Lua version is 5.3 .

Upvotes: 1

Views: 2956

Answers (1)

OK, now I got it. Looking at the source code at https://www.lua.org/source/5.3/lauxlib.c.html#luaL_newmetatable , I noticed that this dual association is done using a "__name" in metatable, rather than using table as key to its name in registry. This behaviour starts with Lua 5.3.

Sample code:

extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

#include <iostream>

struct Object {
    int x;
};

int getMTName(lua_State *L)
{
    lua_getmetatable(L, 1);
    lua_pushstring(L, "__name");
    lua_rawget(L, 2);
    return 1;
}

int main(int argc, char **argv)
{

    lua_State *L =luaL_newstate();
    luaL_openlibs(L);

    Object obj;

    lua_pushcfunction(L, getMTName);
    lua_setglobal(L, "getMTName");

    luaL_newmetatable(L, "my_metatable");

    lua_pushlightuserdata(L, &obj);
    luaL_setmetatable(L, "my_metatable");
    lua_setglobal(L, "obj_");

    int e = luaL_dostring(L, "print(getMTName(obj_))");

    if (e)
    {
        std::cerr << "ERR: " << lua_tostring(L, -1) << std::endl;
        lua_pop(L, 1);
    }

    return 0;

}

Upvotes: 2

Related Questions