lua-users home
lua-l archive

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


On Sat, Nov 26, 2011 at 06:39, Rebel Neurofog <rebelneurofog@gmail.com> wrote:
> On Sat, Nov 26, 2011 at 5:03 PM, Marc Balmer <marc@msys.ch> wrote:
>> Hi
>>
>> I have a stylistic question wrt/ calling Lua "callbacks" from a C
>> program.  I see two obvious approaches:
>>
>> 1) Lua code registers callbacks explicitely using a RegisterCallback
>> function that is provided by the C program; the C program later calls
>> the callback function when one is registered.
>>
>> 2) Lua code does not register callbacks, but the callbacks must be
>> functions with a certain name, e.g. "MouseMovedCallback"; C code will
>> then see if a function with the correct name is available in the Lua
>> state, and if so, call it.
>>
>> Are there advantages of one approach over the other?  Are there other
>> approaches?  If you also use callback written in Lua, which you call
>> from C, I'd like you to share your opinion (and/or experience).
>>
>> I experienced with both forms, I am unsure for which form to go...
>>
>
> I prefer the first case.
> A function may contain also upvalues.
> Here's the code:
>
> local desktop = widget_system.create_desktop ()
>
> -- Case 1
> input.set_mouse_handler (desktop.mouse_move)
>
> -- Case 2
> function mouse_move_handler (dx, dy)
>   desktop.mouse_move (dx, dy) -- note, there's no ":" here
> end
>

Either method can produce either result. Consider:

--foo callback has to be explicitly registered, but just calls a global by name
RegisterCallback('foo', function(...) return MyFooHandler(...) end)

--bar callback is called by name, but just dispatches from a registry table
function MyBarHandler(...) return callbacks.bar(...) end

The former has a few advantages:
1) You can (presumably) set and remove callbacks at will, replace them
with different functions, get the existing function and wrap it, etc.
With the latter method this involves modifying globals which can get
ugly.

2) Scope. Explicit registration means your callbacks don't have to be
global, and as Rebel mentioned can refer to upvalues.

3) I assume calling the callbacks would be a tad more efficient when
using explicit registration, as you'd be storing the functions in the
registry table using luaL_ref and retrieving them using lua_rawgeti.
My gut tells me that looking up integer keys would be faster than
looking up string keys as there's no need to hash anything. Of course
I could be totally wrong.

When I implemented callbacks in Lua in the Mupen64Plus emulator, I
designed a very simple C API intended to be as fast as possible, which
would just retrieve a function from the registry table and call it
unprotected. However by default the program loads a script at startup
which essentially replaces this API; user scripts add their callbacks
to a table, and the startup script, in the function actually called
from C, dispatches each of these in protected mode. So the API is
simple, but if it proves too slow you can modify the startup script
and use the "raw" C API directly. (Some debugging callbacks could be
called as often as every emulated instruction!)
Of course, my main motivation for doing it this way was to write most
of the code in Lua instead of C. :p

-- 
Sent from my toaster.