lua-users home
lua-l archive

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


On 10/7/07, Wesley Smith <wesley.hoke@gmail.com> wrote:
Hi Lua list,
I'm writing some Lua bindings for a C++ library and I'd like the
binding to follow as much as possible the way the library is coded
from C++.  I'm adding higer-level bindings as well, but the base,
low-level bindings I want to closely parallel what a C++ program would
look like.  Here's what I'm binding:

class Voronoi
{

   public:
       const Delaunay & dual()
       {
           return dt;
       }

//everything else left out for simplicity

   protected:
        Delaunay dt;
};

The way this is typically used goes as follows

Voronoi v;
v.dual().is_infinite(point);

I'd like to use it like this in Lua

v = Voronoi()
v:dual(): is_infinite(point)
 
 
My suggestion would be to wrap your structure into a userdata either by value (as you're doing now), or by reference. Add some tag at the start of the userdata block to distinguish which is which, and you can add some flag to indicate whether it's constant too. An additional benefit is that if the script mistakenly call your wrapped functions with a userdata that contains something else altogether, your wrapping code can detect it and issue an error instead of crashing.
 
Then, write two functions that your code would use whenever it needs to retrieve a pointer to a voronoi object:
 
const vdata* to_voronoi_const( lua_State* pLS )
vdata* to_voronoi( lua_State* pLS )
 
 
The former would get the object from the lua stack, verify (or this could be done beforehand) that it's a userdata, check the tag to figure out if it's a reference or value, and return the structure's address.
 
The second function would do the same but would additionally generate a lua error if the userdata is flagged as const.
 
You could also write several functions that would wrap a given vdata either as a value or as a reference. For instance, you'd make dual() return a voronoi wrapped as a reference. And since
is_infinite() would use the to_voronoi_const function above, it would work indiferently with a userdata containing a value or a reference.
 
Of course, you can add some code generation or C++ templates to the mix for easier implementation of this for several different classes.
 
The only issue with this is if the script saves a userdata containing a pointer to a structure, which could be freed in the meantime. In my own project, I don't have this issue because I use smart pointers and if some the script obtains a reference to a struct contained by value as a class attribute, I keep a smart pointer to the class instance in the userdata containing the reference to the struct, so keeping this reference to the struct will also prevent the object it's part of from getting deleted.
 
There could be other solutions to the problem, like some creative overloaded assignment operator that would turn the reference into a copy if the script stores it into a variable.