problem with __eq in metatable

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

problem with __eq in metatable

Brian Segall
[Lua 5.1.1]

I'm trying to override the comparison operator for some tables. I'm using the C API to provide the metamethod. Some pseudo (Lua) code to show my intention:

t1 = {string = "hello"}
t2 = {string = "hello"}
if t1 == t2
   something
end

I would like (t1 == t2) to call my C function, which in this example would access the strings stored in each table, and use strcmp to determine if they're equal.

Here is what I currently have (in C and Lua). I've stepped into the Lua code, and the "__eq" entry is different in the metatables of both tables, therefore it doesn't call my C function to compare strings.

C file:
----------------
static const char* KEY = "string";

static int CompareStrings(lua_State* L)
{
	lua_pushstring(L, KEY);
	lua_gettable(L, 1);
	const char* s1 = lua_tostring(L, -1);
	lua_pop(L, 1);

	lua_pushstring(L, KEY);
	lua_gettable(L, 2);
	const char* s2 = lua_tostring(L, -1);
	lua_pop(L, 1);

	lua_pushboolean(L, (int)!stricmp(s1, s2));

	// on stack: boolean
	return 1;
}

static int newstring(lua_State* L)
{
	const char* s = lua_tostring(L, 1);

	// the table to return (T1)
	lua_newtable(L);
	lua_pushstring(L, KEY);
	lua_pushstring(L, s);
	lua_settable(L, -3);

	// the metatable (T2)
	lua_newtable(L);
	lua_pushstring(L, "__eq");
	lua_pushcfunction(L, CompareStrings);
	lua_settable(L, -3);

	// set T1's metatable to T2 (top of stack)
	lua_setmetatable(L, -2);

	// on stack: table (T1)
	return 1;
}

test.lua:
--------------------
a = newstring("hello")
b = newstring("hello")
if a == b then
	print("they are equal")
else
	print("they are not equal")
end


----------------------

It always prints "they are not equal" since my comparison function is not being called. luaO_rawequalObj in lobject.c is where the __eq methods are determined to be different, and lacking a comparison handler Lua returns false.

Thanks for the help.

Brian

_________________________________________________________________
Deck to dock: outfit your cottage in stylish comfort. Check out Sympatico / MSN Shopping for great Cottage Living ideas. http://shopping.sympatico.msn.ca/category/shp/?bCatID=11,ptnrid=176,ptnrdata=081801


Reply | Threaded
Open this post in threaded view
|

Re: problem with __eq in metatable

Luis Carvalho-2
On Sat, Aug 26, 2006 at 10:10:23AM -0700, Brian Segall wrote:
<snip> 
> test.lua:
> --------------------
> a = newstring("hello")
> b = newstring("hello")
> if a == b then
> 	print("they are equal")
> else
> 	print("they are not equal")
> end
> 
> 
> ----------------------
> 
> It always prints "they are not equal" since my comparison function is not 
> being called. luaO_rawequalObj in lobject.c is where the __eq methods are 
> determined to be different, and lacking a comparison handler Lua returns 
> false.

The manual states that

"'eq': the == operation. The function getcomphandler defines how Lua chooses a
metamethod for comparison operators. A metamethod only is selected when both
objects being compared have the same type and the same metamethod for the
selected operation."

And so your problem is that you don't have same metamethod for a and b in your
example above, since you create a new closure for CompareStrings in their
metatables. Check getmetatable(a).__eq and getmetatable(b).__eq.

One possible solution is to create a metatable, save it in the registry, and
use it for your newstrings. Somewhere in your module initialization
(luaopen_xxx), say

luaL_newmetatable(L, "newstring_mt");
lua_pushcfunction(L, CompareStrings);
lua_setfield(L, -2, "__eq");

Then, in newstring, instead of creating a new metatable and a new closure, do

- 	lua_newtable(L);
- 	lua_pushstring(L, "__eq");
- 	lua_pushcfunction(L, CompareStrings);
- 	lua_settable(L, -3);

+	lua_getfield(L, LUA_REGISTRYINDEX, "newstring_mt");

Check that now getmetatable(a).__eq == getmetatable(b).__eq, and your example
should work.

Cheers,
Luis.

-- 
A mathematician is a device for turning coffee into theorems.
        -- P. Erdos 

-- 
Luis Carvalho
Applied Math PhD Student - Brown University
PGP Key: E820854A <[hidden email]>