5
\$\begingroup\$

I'm writing a game engine that uses C++ and Lua (and Luabind).

Currently, I'm writing all the bindings inside the constructor of the class being binded. I really don't like this because it's cluttering up my code.

Where should I put the Lua glue code so that it is out of the way and not cluttering up my codebase?

\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

The method I have used with good results is to give each class that needs Lua bindings a static class method with the following signature:

static luabind::scope luaBindings(); 

The definition of this method looks like this:

luabind::scope MyClass::luaBindings() { using namespace luabind; return class_<MyClass>("MyClass") .def(constructor<>()) .def("someMethod", &MyClass::someMethod) ; } 

Then, in some other place, I initialize the Lua state like this:

void initializeLua( lua_State* L ) { luabind::open(L); luabind::module(L) [ MyClass::luaBindings(), MyOtherClass::luaBindings() ]; } 

This way, all Lua bindings are contained in the static class methods. The Lua state is initialized in a very controlled way, without headaches about the order that classes are exported in.

The only downside I have encountered so far is that the initializeLua function needs to know all the classes being exported. Depending on the number of classes, this will result in a rather large list of included files and potentially long compilation times. If that's an issue for you, you can build the luabind::scope hierarchically like this:

luabind::scope moduleABindings() { return ( MyClass::luaBindings(), MyOtherClass::luaBindings() ); } luabind::scope moduleBBindings() { return ( Foo::luaBindings(), Bar::luaBindings() ); } void initializeLua( lua_State* L ) { luabind::open(L); luabind::module(L) [ moduleABindings(), moduleBBindings() ]; } 

By separating those functions into separate compilation units, a small change in one of the exported classes' headers will not require recompiling the whole initializer, just the module that has changed.

\$\endgroup\$
3
  • \$\begingroup\$ This is neat. Could you briefly explain what this is/does? class_<MyClass>("MyClass") .def(constructor<>()) .def("someMethod", &MyClass::someMethod) I'm having trouble understanding it. \$\endgroup\$ Commented Jul 15, 2013 at 23:43
  • 1
    \$\begingroup\$ @StevenLu That line exports the MyClass class with an empty constructor to the Lua scripting engine followed by defining a method someMethod on Lua's MyClass definition and that method call invokes the C++ method MyClass::someMethod. \$\endgroup\$ Commented Jul 16, 2013 at 4:32
  • \$\begingroup\$ Is constructor<> a type defined by Lua's C++ API? Last I played with Lua it had no C++ stuff. edit: Ah, I recognize it now. It's Luabind! \$\endgroup\$ Commented Jul 16, 2013 at 5:51
4
\$\begingroup\$

0) Move your constructor to a separate file, there's no rule that says your entire class has to be all in one physical .cpp file.

1) Put your binding code in a separate function in a different file, have the constructor call it? This would be the preferred method.

2) write your binding code in a separate file, inline, and #include it directly into your constructor. This is an oldschool way to get around, not so great these days.

fn::fn() { #include "clutter.txt" } 

At least that way it's only cluttering up your project and not the code you see on a daily basis.

\$\endgroup\$
1
  • \$\begingroup\$ There's no reason it has to be in the constructor for the object. I just put it there because it was the simplest place to put it. I'd rather have it out of the class entirely. \$\endgroup\$ Commented Jul 15, 2013 at 3:34

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.