lua-users home
lua-l archive

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


As the implementation did, it only checks the first object wether it has a __call method in its metatable. If not, it raises an error, instead of checking the next object. But it seems not clear in the docs.

rwen

/*
** Check whether __call metafield of 'func' is a function. If so, put
** it in stack below original 'func' so that 'luaD_precall' can call
** it. Raise an error if __call metafield is not a function.
*/
static void tryfuncTM (lua_State *L, StkId func) {
  const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
  StkId p;
  if (!ttisfunction(tm))
    luaG_typeerror(L, func, "call");
  /* Open a hole inside the stack at 'func' */
  for (p = L->top; p > func; p--)
    setobjs2s(L, p, p-1);
  L->top++;  /* slot ensured by caller */
  setobj2s(L, func, tm);  /* tag method is the new function to be called */
}


------------------ 原始邮件 ------------------
发件人: "Francisco Olarte";<folarte@peoplecall.com>;
发送时间: 2017年2月20日(星期一) 晚上8:15
收件人: "Lua mailing list"<lua-l@lists.lua.org>;
主题: __call metamethod, misleading doc or am I missing something?

If I make a table callable everything is fine:

>>>>
~ $ lua
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> function f1(...) print("f1", ...) end
> f1
function: 0x1e92c70
> o1 = setmetatable({},{__call=f1})
> o1
table: 0x1e94580
> o1(1,2,3)
f1    table: 0x1e94580    1    2    3
<<<<

But then if I try this it barfs:

>>>
> o2 = setmetatable({},{__call=o1})
> o2
table: 0x1e95c50
> o2(4,5,6)
stdin:1: attempt to call a table value (global 'o2')
stack traceback:
    stdin:1: in main chunk
    [C]: in ?
<<<

The error message puzzled me, specially since it mentioned o2, which
has the same 'shape' as o1 ( and did not say '__call metamethod must
be a function' )

Given the manual says:

>>
__call: The call operation func(args). This event happens when Lua
tries to call a non-function value (that is, func is not a function).
The metamethod is looked up in func. If present, the metamethod is
called with func as its first argument, followed by the arguments of
the original call (args). All results of the call are the result of
the operation. (This is the only metamethod that allows multiple
results.)
<<

I was expecting the following.

Try to call o2, o2 is not a function. Get _call metamethod, it is o1.
Try to call it. It is not a function, enter the __call handling again
and get to f1.

Reading "2.4 – Metatables and Metamethods" the only hint I get of
metatable methods needing to be functions is the end of the first
paragraph " Lua checks for a function in the field "__add" of the
value's metatable. If it finds one, Lua calls this function to perform
the addition. ".

But if I use a 'callable' with __add it seems to work:

>>>
> p1 = setmetatable({},{ __call = function(me, t, x ) return { val = t.val + x}; end })
> t = setmetatable({val=3}, { __add=p1 })
> tt = t+5
> for k,v in pairs(t) do print(k,v) end
val    3
> for k,v in pairs(tt) do print(k,v) end
val    8
<<<

So, if the metamethod for __call NEEDS to be a real function, I think
it should be clearly indicated in its documentation.

(
Note, I know I can use a closure:
>>>
> function force_func(f) if type(f)=="function" then return f else return function(...) return f(...) end end end
> o3 = setmetatable({},{__call=force_func(o1)})
> o3
table: 0x1e98800
> o3(7,8,9)
f1    table: 0x1e94580    table: 0x1e98800    7    8    9
<<<
to do it, so it's not a big problem, but I think the doc should make it clearer
)

Francisco Olarte.