Sol2: Setting a function that's defined using Lua?

Created on 16 May 2017  路  3Comments  路  Source: ThePhD/sol2

I'd like to define a function in Lua code and then use sol2 to bind that function to a module table. My initial idea was to use sol::function fn = lua.script("return function() return 5 end") and then tbl.set_function("fnName", fn), but it's behaving strangely; fnName will be of type function, but calling it will always return nil (note, though, that the function does get executed, it's just the returns that don't get retrieved).

I'm unsure if this sort of thing is meant to be possible in the first place, or if I'm binding it incorrectly, or what.

Test code (Lua v5.1.5, Sol2 v2.17.3):

#define SOL_CHECK_ARGUMENTS
#include <catch.hpp>
#include <sol.hpp>

TEST_CASE("setting a function returned from Lua code")
{
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    sol::function fn = lua.script("return function() return 5 end");

    // this works as expected
    SECTION("getting the value from C++")
    {
        int result = fn();
        REQUIRE(result == 5);
    }

    // this won't work, the return is nil
    SECTION("setting the function directly")
    {
        lua.set_function("test", fn);

        REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
        REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)"));
        REQUIRE_NOTHROW(lua.script("assert(test() == 5)"));
    }

    // this will print 'this was executed'
    SECTION("does the function actually get executed?")
    {
        sol::function fn2 = lua.script("return function() print('this was executed') end");
        lua.set_function("test", fn2);

        REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
        REQUIRE_NOTHROW(lua.script("test()"));
    }

    // this works
    SECTION("setting the function indirectly, with the return value cast explicitly")
    {
        lua.set_function("test", [&fn]() { return fn.call<int>(); });

        REQUIRE_NOTHROW(lua.script("assert(type(test) == 'function')"));
        REQUIRE_NOTHROW(lua.script("assert(test() ~= nil)"));
        REQUIRE_NOTHROW(lua.script("assert(test() == 5)"));
    }
}

Results:

-------------------------------------------------------------------------------
setting a function returned from Lua code
  setting the function directly
-------------------------------------------------------------------------------
..\module_function.cpp(18)
...............................................................................

..\module_function.cpp(23): FAILED:
  REQUIRE_NOTHROW( lua.script("assert(test() ~= nil)") )
due to unexpected exception with message:
  lua: error: [string "assert(test() ~= nil)"]:1: assertion failed!

this was executed
Bug.Well Shit

All 3 comments

This exposes what is technically a bug in the set_function path. set_function is meant to be used with C++ functions and does its damndest to deduce return type, arguments, and other signature information, as well as bundle it up in a way that's usable. What it does not account for is someone having a sol::function already.

Your code would work just by doing lua.set( "test", fn ); But, I still consider it an oversight for set_function to not handle what is sol2's basic functional type. I'll have to patch this in and backport it into 2.17.3. Thanks for reporting.

Ah, cool, thanks for the clarification. set does indeed work.

Backported, your original code will work:

https://github.com/ThePhD/sol2/releases/tag/v2.17.3

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mrgreywater picture mrgreywater  路  4Comments

shohnwal picture shohnwal  路  10Comments

karenzshea picture karenzshea  路  4Comments

TheMaverickProgrammer picture TheMaverickProgrammer  路  6Comments

Murloc992 picture Murloc992  路  7Comments