lua-users home
lua-l archive

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


I have come across something that I am unsure if it is expected behaviour or a bug and would like some help to identify which it is.
Without going into too much detail I am trying to use the metamethod "__eq" using two full userdata types which both have different metatables yet the same metamethod. According to what I have reread in Programming in Lua and the Reference Manual this should work and does so for tables yet not userdata.
Here is the Lua code for tables:
mt1 = {}
mt2 = {}

equal = function (lhs, rhs)
return lhs.i == rhs.i
end

mt1["__eq"] = equal
mt2["__eq"] = equal
t1 = {}
setmetatable(t1,mt1)
t2 = {}
setmetatable(t2,mt2)
t1.i = 1
t2.i = 1
assert(t1 == t2)

As you can see it is two tables with different metables yet with the same metamethod which according to the Reference Manual would work.
http://www.lua.org/manual/5.1/manual.html#2.8

When I try a similar thing with full userdata instead of tables the method is not called and it returns false, yet I feel it should not. Here is example C++ code for that, (forgive me it takes a bit more code to do this):
First the userdata structure and the method

struct Int_wrapper{int i;};

int equal(lua_State* s)
{
    Int_wrapper* i1 = static_cast<Int_wrapper *>( lua_touserdata(s, 1) );
    Int_wrapper* i2 = static_cast<Int_wrapper *>( lua_touserdata(s, 2) );
    lua_pushinteger(s, i1->i == i2->i ? 1 : 0 );
    return 1;
}

        lua_State* s = luaL_newstate();
        std::string chunk("equal = function (lhs, rhs) \
                          return lhs == rhs \
                          end");
        luaL_loadbuffer(s,chunk.c_str(),chunk.size(),"userChunk");
        lua_pcall(s,0,LUA_MULTRET,0);
        lua_getfield(s, LUA_GLOBALSINDEX, "equal");

        luaL_newmetatable(s, "mt1");
        int mt1 = lua_gettop(s);
        luaL_newmetatable(s, "mt2");
        int mt2 = lua_gettop(s);

        lua_pushliteral(s, "__eq");
        lua_pushcfunction(s, &equal);
        lua_settable(s, mt1);

        lua_pushliteral(s, "__eq");
        lua_pushcfunction(s, &equal);
        lua_settable(s, mt2);

        Int_wrapper* wrapper1 = static_cast<Int_wrapper*>(lua_newuserdata(s, sizeof(Int_wrapper)));
        int w1 = lua_gettop(*m_lua);
        lua_pushvalue(*m_lua,mt1);
        lua_setmetatable(*m_lua,w1);

        Int_wrapper* wrapper2 = static_cast<Int_wrapper*>(lua_newuserdata(s, sizeof(Int_wrapper)));
        int w2 = lua_gettop(s);
        lua_pushvalue(s,mt2);
        lua_setmetatable(s,w2);

        wrapper1->i = wrapper2->i = 1;
        lua_remove(s,mt1);
        lua_remove(s,mt1);

        lua_pcall(s,2,LUA_MULTRET,0);
        int result = lua_tointeger(s,-1);
        CPPUNIT_ASSERT_EQUAL(1,result);
        lua_close(s);


Could some confirm that this should or should not work, if it should not could you please explain why?
Thanks