lua-users home
lua-l archive

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


Dear. Mr. Conner,

My main application is C++, and it embeds lua (though sometimes it relinquishes full control to a lua loop), so I needed something a bit strong to handle my needs.

Thusly, Yes[1]. Given this lua code:

    function f (num_value, a)
        return num_value * 2, a:bark()
    end
    nested = { variables = { no = { problem = 10 } } }


And a sprinkling of C++ code that we'd like to call from Lua that has the exact same behavior:

    struct A {
        int a = 0xA;
        virtual int bark() { return 1; }
    };

    std::tuple<int, int> bark(int num_value, A* a) {
        return std::tuple<int, int>( num_value * 2, a->bark() );
    }

You can start things off and do the following, which creates lua state and sets up a new userdata to behave as you would expect from the given lua:

    sol::state lua;
    lua.script( script_string );
    // can also do lua.script_file( file_name ); too
    lua.new_usertype<A>( "A",
        "bark", &A::bark
    ); // have a struct and its functions set into this table (coincidentally, it's the global table)

    // set the C++ function "bark" to lua identifier "g"
    lua.set_function("g", bark);

The following code will do (I believe) what you ask for, calling both a lua function and a C++ function with the (table-nested) lua variable and the C++ variable:
   
    sol::function cpp_bark = lua["f"];
    sol::function lua_bark = lua["g"];
    sol::reference lua_variable_x = lua["nested"]["variables"]["no"]["problem"];
    A cpp_variable_y;
    std::tuple<int, int> cppresult = cpp_bark(lua_variable_x, cpp_variable_y);
    std::pair<int, int> luaresult = lua_bark(lua_variable_x, cpp_variable_y);


This returns the correct result for both cppresult, which calls the C++ function, and luaresult, which handles multiple returns from lua and returns those as well (expected: a pairing of { 20, 1 }). The example here is a bit squished since I wanted to pack it dense, but I can guarantee you the amount of code you'd write in the plain C API would be a bit of a heartbreaker to achieve the same effect.

Note that the actual code actually "registers" the usertype "A" into lua. If you wanted this code to be tiny, you could remove that part of the example and .

- ThePhD

[1] And here's the code running: http://i.imgur.com/nJDfLHw.png

But you don't have to believe the image, give it a whirl if you like!
Repo - https://github.com/ThePhD/sol2
Full Code - https://gist.github.com/ThePhD/470a3345d78f1ea4d291

On Mon, Mar 14, 2016 at 5:22 PM, Sean Conner <sean@conman.org> wrote:
It was thus said that the Great ThePhD once stated:
> Dear Everyone,
>
> I *STRONGLY *disagree with always defaulting to the C API. While it's good
> for quick things and hobby projects, the C API lacks the ability to scale.
> Writing large applications where you're writing -- and re-writing (or
> copy-pasting) -- the same code over and over again with slight tweaks just
> to call a function or something is not okay.

  I've found that I rarely ever call more than one Lua function from C code,
and that's usually to start the Lua code running.  The C code exists to do
those things that I cannot do from Lua (create a socket, convert an Xlib
event to a Lua table, etc).  The main application is written in Lua.  If I
wanted to write an application in C, I know where to find it.

> This is *BAD*. It's error-prone. It's sluggish. It's just not what you want
> out of an API. If I can do
>
> f("hi", 24, 56)
>
> In Lua, I deserve something that allows me to do
>
> f("hi", 24, 56)
>
> In C++. We can tote how easy it is to use the Lua C API -- and it's fine
> for implementing things quickly or being the underpinnings of a library --
> but it is NOT ideal. It is NOT the best we can do. We can do better. And we
> do deserve to have libraries that make it better. Libraries that allow us
> to do [ Selfish plug ]:
>
> sol::function f = table["f"];
> f("hi", 24", 56);

  Okay, so does your binding library handle this?

        sol::function f = table["g"];
        g(lua_variable_x,cpp_variable_y);

(and just in case it isn't clear, "lua_veriable_x" is a variable defined in
the given Lua state, and cpp_variable_y is a C++ variable).

  -spc