lua-users home
lua-l archive

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


On Wed, Dec 22, 2010 at 7:26 PM, Ronald Lamprecht
<R.Lamprecht@t-online.de> wrote:
> Hi,
>
> Am 22.12.2010 18:20, schrieb Peter Cawley:
>>
>> On Wed, Dec 22, 2010 at 5:14 PM, Ronald Lamprecht
>> <R.Lamprecht@t-online.de>  wrote:
>>>
>>> What is the favorite design of a dynamic method dispatcher, that allows
>>> an
>>> object to process arbitrary method calls on demand?
>>>
>>> Due to the manual chapter 2.5.8 (funciton calls) a method call
>>> v:name(...)
>>> is syntactic sugar vor v.name(v,...). This allows you to implement a
>>> static
>>> method dispatcher by storing the various static method functions in the
>>> metatable at their given method names.
>>>
>>> But a dynamic method dispatcher is a single function that needs the
>>> method
>>> name as arguement when being called. It is easy to return the unique
>>> dispatcher function on every call of v.name . But the method name can not
>>> be
>>> stored in the metatable of v because such method calls can be recursiv
>>> and
>>> the arguements of the first call are evaluated between evaluation of
>>> v.name
>>> and its related function call execution.
>>>
>>> The most perfect solution would be if v:name(...) would be syntactic
>>> sugar
>>> vor v.name(v, name, ...). But I guess this would cause major trouble and
>>> incompatibilities.
>>>
>>> For a major Lua project (Enigma) I implemented a LIFO stack for the
>>> called
>>> method names. This works perfect in praxis as long as no one intervens
>>> the
>>> stack by executing v.name, storing its return value and calling it
>>> multiple
>>> times.
>>>
>>> What alternativ implementation patterns are known and which are
>>> recommended?
>>
>> Use closures to remember the name of the method?
>>
>> local v = {}
>> local make_dispatcher = setmetatable({}, {__mode = "k", __index =
>> function(t, k)
>>   t[k] = function(self, ...)
>>     return dispatch(self, k, ...)
>>   end
>>   return t[k]
>> end
>> })
>> setmetatable(v, {__index = function(t, k)
>>   return make_dispatcher[k]
>> end})
>
> I did not mention that the objects are C++ objects that are accessible as
> Lua userdata. Even the dispatcher is a C function.

Closures can just as easily be made in C:

int dispatcher(lua_State *L)
{
    /* Method name at lua_upvalueindex(1)
     Arguments at 1 through N */
}

int index_metamethod(lua_State *L)
{
    lua_pushcclosure(L, dispatcher, 1);
    return 1;
}