lua-users home
lua-l archive

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


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.