Tuesday, May 3, 2011

A function expects a C++ object of abstract type A. How do I pass it a Lua object of an A subclass?

I'd like to pass to a function expecting a C++ object of a pure virtual class a Lua object of a class that derives from the pure virtual C++ class. How can I do this?

I'm new to lua and luabind so bear with me.

In C++:

struct A {
  virtual void foo() = 0;
};

void do_something(A* a) {
  a->foo();
}

In Lua:

class 'MyA' (A)
....
function MyA:foo()
  print('hi')
end

In C++ again:

... // somehow create an instance of MyA class and named myA
    // How? 
    // Maybe the result of a call to "MyA()"?

do_something(myA);
From stackoverflow
  • You would have to create a C++ class which implements your pure virtual function, then calls the Lua code. The implementation would be too complicated to just throw in here.

    Basic pseudo code:

    // C++
    struct LuaA : public A
    {
      LuaA(const std::string &luacode)
        : myLuaHandler(luacode)
      {
      }
    
      virtual void foo()
      {
        myLuaHandler.call("MyA:foo()");
      }
    }
    

    That example is very high level, but it's meant to show that what you want to do is non-trivial. It's the new "LuaA" that you would want to actually expose to your Lua code.

    In general I prefer to use SWIG when wrapping my C++ for exposure to Lua and other scripted languages. SWIG does support this overloading of virtual methods that you are interested in (called "directors" in SWIG parlance), however, it should be noted that Lua/SWIG does not support directors. Java, C#, Ruby, Perl and Python do all have directors support in SWIG. I'm uncertain as to exactly why it is not supported in Lua.

    It is possible, that since Lua does not support inheritance, the exact semantics of what you would like to accomplish are simply not possible in the way you propose.

    Perhaps someone else has a better answer to the Lua side of things?

    z8000 : This is similar to Aaron's solution below. I think this is probably the method I will go with. It's tedious but it'll work. Thanks!
  • See section 10.1 in the LuaBind documentation. You basically provide a simple C++ wrapper to the LuaBind class that acts as a pass through to the underlying Lua implementation. Notice the following from this doc:

    virtual void f(int a) 
    { 
        call<void>("f", a); 
    }
    

    call("f", a) will invoke the Lua 'f' function, passing in the argument a.

    z8000 : Yeah I was trying to avoid this since it's rather tedious but I suppose once it's setup, I'm done. OK, thanks!
  • Sorry, I would not answer the question you've asked directly, but will offer a bit of advice from personal experience instead:

    If you're new to Lua, you should seriously consider writing your first bindings in raw Lua API and without such object-oriented layout. At least you will understand what is really going on.

    Lua API is quite comfortable to use by itself. It does not create any extra overhead and you're in full control on what is happening. Luabind library development is a bit stale at the moment (but it looks like it comes back to life though).

    You should consider if you really need to imitate deriving from C++ classes in Lua-side and, especially, on C++-side. Such thing is not-so-natural for Lua and requires noticeable overhead to be implemented. Furthermore, in C++ you're hiding the fact that you're making a non-native call to another language. Unless well documented, this is a potential source for performance issues.

    When I've started working with Lua a few years ago, I've used to write bindings in the same way as you do, with Luabind, and imitating deriving from C++ objects. Now I'm using pure Lua API and simplistic procedural (as opposed to object-oriented) cross-language interface. I'm a lot happier with the result.

    z8000 : These are definitely valid concerns. The reason for this question is that I'm already using a class-based system (Apache Thrift) and want to implement the service handler in Lua instead of C++. I was trying to avoid the pattern where I implement the service handler in C++, and the methods thereof essentially just call Lua. I was hoping to just make a subclass in Lua itself. Alas, I think I'll go with essentially a mix of all three solutions posted so far (Alexander, Aaron, lefticus). Thanks!
  • I will subclass the pure virtual class in C++ and then likely start with luabind (as per Aaron and lefticus' solutions). If this overhead is too great, I will just use the straight Lua C stack-twiddling API (as per Alexander).

    Thus, there's no one answer here. I will post a comments with results later.

    Thanks everyone!

0 comments:

Post a Comment