[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: is "__metatable" an event similar to "__gc" and "__tostring" or is it a convention?
- From: Peter Shook <pshook@...>
- Date: Sun, 06 Jul 2003 11:21:12 -0400
Vijay Aswadhati wrote:
I have been studying some of the examples such as
"UserDataWithPointerExample"
on the Wiki as well as some real code like the gdbm binding by LHF.
I tried LHF's approach and found out obviously it works as well, however
I am unable to figure out what exactly is the magic behind the statement
"gdbm.metatable.__index=gdbm"
Regarding __metatable, Adam has explained it very well. My example will
work without it. I only added it so that one cannot alter the
userdata's real metatable from a Lua script. The Lua function
getmetatable will return the table of methods instead of the real metatable.
All Lua function are written in the Lua C API, and they are fairly easy
to understand. If you look at lua-5.0/src/lib/lbaselib.c you'll see:
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or
metatable */
}
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
I don't have a current copy of lgdm.tar.gz, and the site is down, so I
cannot explain LHF's code right now. But it appears that he puts the
real metatable in the table of methods, and the index event uses the
table of methods. Something like:
gdbm = {} -- table of methods
gdbm.metatable = { __index = gdbm } -- real metatable
It's hard to explain without diagrams.
The metatable magic is the same for Lua tables as it is for userdata, so
it's best to experiment with Lua tables first.
Play around with this example first.
$ cat x.lua
local methods = {
show = function(t, ...) return t, t.x, t.y, unpack(arg) end,
dot = function(t1, t2) return t1.x * t2.x + t1.y * t2.y end,
common = 'this is common',
}
local mt = {
__index = methods,
__tostring = function(t) return 'this object is '.. t.name end,
}
obj1 = { name = 'bob', x=0, y=2 }
setmetatable(obj1, mt)
obj2 = { name = 'bill', x=4, y=3 }
setmetatable(obj2, mt)
$ lua -lx -i
> = obj1, obj1.common
this object is bob this is common
>
> = obj2, obj2.common
this object is bill this is common
>
> = obj1:show('a','b')
this object is bob 0 2 a b
>
> = obj2:show'cow'
this object is bill 4 3 cow
>
> = obj1:dot(obj2)
6
>
Then read:
http://lua-users.org/lists/lua-l/2003-05/msg00287.html
I hope this helps. Let us know if you have more questions.
There isn't a lot of magic to it. Once you have a mental image of how
it works, it's pretty straight forward. I started to make some diagrams
but then I got lazy. I'll try to finish them.
- Peter