C binding strategy

  • From: Francisco Tolmasky <tolmasky@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Wed, 15 Aug 2012 17:46:50 -0700

I asked a question similar to this on the normal lua mailing list, and one of 
the primary suggestions was to first switch to luajit to be able to take 
advantage of the very cool ffi feature. I took yesterday to port my project to 
luajit and now am hoping the luajit community can provide some guidance in the 
next steps.

Basically, I am trying to bridge events from C into Lua. For example, lets say 
a Point class (containing x and y). These points get used internally by the C 
code to do graphics stuff, etc (or say Quaternions, etc.). The point is, I'm 
referring to simple objects that you might use a struct for, would rarely have 
a pointer for in C or a non-trivial lifetime like an "Image" class or something.

1. I would *like* to have as much be done in Lua as possible. As such one 
strategy is from C to use the lua APIs to create a traditional table in lua 
code, then when I need something in C, operate on the table using the old API 
loa_gettable etc. So for example, I'll have a table with x and y keys in Lua, 
then when I pass it to one of the graphics library functions, it checks its 
metatable to make sure its the right kind of object (or maybe even just check 
that it has number x and y), and use whatever it needs from it. This is 
certainly more in the "spirit" of lua I feel, and I don't mind the extra work 
of writing it. Similarly, when I need to return a point from C, I actually 
create the table (or load a chunk that calls the "constructor" defined in Lua). 
Hence, all my objects are always "real" Lua objects (and easy to reason about 
with regard to gc etc):

void mouseUpdated(point p)
{
        // Make a Point. "Point" is defined in Lua land
        lua_getglobal(L, "Point");
        lua_pushnumber(L, p.x);
        lua_pushnumber(L, p.y);
        lua_pcall(L, 2, 1, 0);

        // Send it on over as the sole argument to mouseUpdated
        lua_getglobal(L, "mouseUpdated");
        lua_pcall(L, 1, 0, 0);
}

2. However, in some runtimes, the general advice is "the more you can have in 
C, the better". For example, in JavaScriptCore "doing JS from C++" (or even 
ObjC) is almost always way faster than having it happen as interpreted code in 
the interpreter. This is true even given the cost of bridging JS strings to 
NSString etc. As such, in the Point example, another approach would be to use 
the FFI to bridge over point structs for instance (as I believe there is an 
example on the website), and also map over all the methods to C functions. From 
the vanilla lua implementations (and libraries like LuaBind) I got the 
impression that this might not be as beneficial in Lua though.

So basically, either dealing with a C exposed object in Lua, or dealing with a 
Lua table in C. From the examples given on the website, I can see the obvious 
benefits for large arrays of doubles and alternatively for complex C/C++ 
objects, but I am not sure about these kinds of "in between" objects. Is FFI so 
much better/faster that I should just go for it? For objects like 
points/quaternions/mouseevents/whatever will I be saving a ton of memory? Also, 
although FFI certainly seems faster than the traditional Lua C bindings, its 
still not clear to me if its faster than normal code, if that makes sense.

Apologies if some of this stuff has been covered already, I am new to Lua so 
I'm not sure if one is obviously better than the other. I would like to gain an 
intuition for when its desirable to bridge to C and when not.

Thanks!

Francisco


Other related posts: