lua-users home
lua-l archive

Re: rethinking method calls with __mcall metamethod rather than __index/__call

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


On Sat, Jun 13, 2009 at 5:04 PM, Mark Hamburg wrote:
> It also allows for mixing efficient method inheritance
> with property accessors because __mcall could lead to a table of methods
> while __index could lead to a function that did the property accessor logic.
Which according to [1], I gather you mean
 mt.__mcall = methods -- remains fast
 function mt.__index(t, k) -- slower
 local p = properties[k]
 if p then return p(t, k) end
 error("Unknown property: " .. tostring(k))
 end
> The semantics of __mcall would be something like the following (which
> essentially corresponds to the self opcode):
>
>        function mcallprep( t, k )
>                local mt = getmetatable( t )
>                local mcall = mt and mt.__mcall
>                if mcall then
>                        if type( mcall ) == 'table' then
>                                return mcall[ k ], t
>                        else
>                                local f, o = mcall( t, k )
>                                return f, o
>                        end
>                end
>                return t[ k ], t -- Uses standard lookup
>        end
The "set" example above, in which __mcall will be a table, can be well
represented that way:
 -- Simple Set ADT
 local mt = {}
 local methods = {}
 function methods:union(set2)
 for k in pairs(set2) do self[k] = true end
 end
 mt.__mcall = methods
 function set(t)
 local self = setmetatable({}, mt)
 for _,v in ipairs(t) do self[v] = true end
 return self
 end
 -- note: optionally share mt and methods in same table,
 -- which as a side-effect exposes __mcall as a method.
However, the proxy example, in which __mcall will be a function,
involves a temporary closure again, and we prefer to be able to omit
the "o" value above too:
 -- Proxy
 local mt = {}
 function mt:__mcall(k)
 local priv = self[1]
 return priv:[k] -- note: omit ",o"
 end
 function mt:__index(k)
 local priv = self[1]
 return priv[k]
 end
 function proxy(o)
 return setmetatable({o}, mt)
 end
The awkwardness lies in that "local f, o = mcall( t, k )" deconstructs
the method in terms of a function and its first argument, but the
proxy doesn't necessary have access to the original f, which as you
noted is no longer loose.
> Finally, one could argue that adding this feature essentially necessitates
> method currying...
i.e. [2]
Also, in [3] you wrote:
> Finally, it would be good to have a fast way to test for method
> support. These changes would essentially force the use of obj:msg
> for any object using the new __self metamethod, but since that
> actually constructs a closure, it's overkill if all we want is a boolean.
True, but in similar fashion neither do we have an efficient way to
test for operator support (e.g. call operator) [4]. Indexing was an
incomplete solution for that anyway. We might write obj:__call or
obj:["()"] to obtain a closure (or nil) for the call operation.
[1] http://lua-users.org/lists/lua-l/2006-04/msg00527.html
[2] http://lua-users.org/wiki/MethodCurry
[3] http://lua-users.org/lists/lua-l/2009-01/msg00612.html
[4] http://lua-users.org/lists/lua-l/2009-05/msg00479.html

AltStyle によって変換されたページ (->オリジナル) /