lua-users home
lua-l archive

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


Hello,

Thank you all for your quick replies. We have looked into them and found out the following:

lua_yield() and lua_yieldk() do not solve the problem I addressed in my original post. When you use lua_yield() or lua_yieldk() in a C function, you cannot resume at the next statement after the yield call and continue the C function from there, because the C stack was obliterated when yielding. 
With lua_yieldk() you at least have the opportunity to provide a continuation function, but still you cannot resume after the yield call, only at the continuation function. That complicates the code, because you have to take care of keeping track of the state of the program when yielding (i.e. what the stack is supposed to do for you)
What we are suggesting is a yield function in C that works same as the familiar yield in Lua: When you call resume, the coroutine continuous after the yield call.

Let me illustrate the problem in a simple code example: a recursive function producing the Fibonacci sequence. There is one implementation with lua_yieldk() (Example fibYieldK), another with our suggested changes in the Lua interpreter (Example fibFiber), and a third (Example fibLua) in Lua. 
In Example fibFiber you see that our new yield function for the Lua interpreter allows the Fibonacci sequence to be implemented with a clean recursive function. The function returntofiber()works in C exactly like yield does in Lua. That means when you call resume, the execution continues after the call to returntofiber(). 
However in Example fibYieldK (with lua_yieldk()) you have to modify the function and have to declare extra variables, structs, etc. to save the actual state, to get the desired result.

I also implemented the Fibonacci sequence in Lua, as you can see the Lua function and the C function of Example fibFiber can be implemented in the same way.

Best regards,
Lukas


Example fibYieldK (Fibonacci sequence in C with lua_yieldk()):

typedef struct GeneratorState {
	int a;
	int b;
	int limit;
	int counter;
} GeneratorState;

static int recFibYieldK(lua_State* L, int status, lua_KContext ctx) {
	GeneratorState* state = (GeneratorState*)ctx;
	int fib = state->a + state->b;
	state->counter += 1;
	if (state->counter >= (state->limit - 1)) {
		lua_pushnumber(L, fib);
		return 1;
	}
	state->a = state->b;
	state->b = fib;

	lua_pushinteger(L, state->a);
	return lua_yieldk(L, 1, (lua_KContext)state, recFibYieldK);
}

static int fibYieldK(lua_State* L) {
	int number = lua_tonumber(L, -1);
	GeneratorState* state = lua_newuserdata(L, sizeof(GeneratorState));
	state->a = 0;
	state->b = 1;
	state->counter = 0;
	state->limit = number;
	lua_pushinteger(L, state->a);
	return lua_yieldk(L, 1, (lua_KContext)state, recFibYieldK);
}


Example fibFiber (Fibonacci sequence in C (with our changes in the Lua interpreter)):

static int recFibFiber(int n) {
	if (n == 0) {
		return 0;
	}
	if (n == 1) {
		return 1;
	}
	lua_returntofiber(1);
	return (recFibFiber(n - 1) + recFibFiber(n - 2));
}

static int fibFiber(lua_State* L) {
	int number = lua_tonumber(L, -1);
	int result = recFibFiber(number);
	lua_pushnumber(L, result);  // result
	return 1;
}


Example fibLua (Fibonacci sequence in Lua):

function fib.fib_Lua(num)
    if(num == 0) then
        return 0
    end
    if (num == 1) then
        return 1
    end
    coroutine.yield()
    return (fib.fib_Lua(num - 1) + fib.fib_Lua(num - 2))
end


Lua main:

local fibYieldK_dll = require("fibYieldK")
local fibFiber_dll = require("fibFiber")
local fibLua_lua = require("fibLua")

local finished = false
local fibNum = 6

local _corFibFiber = coroutine.create( function()
        local retValFiber = fibFiber_dll.fib_fiber(fibNum)
        print("fibonacci corFibFiber: " .. retValFiber)
        finished = true
end)

local _corFibYieldK = coroutine.create( function()
    local retValLuaC = fibYieldK_dll.fib_yieldK(fibNum)
    print("fibonacci corFibYieldK: " .. retValLuaC)
end)

local _corFibLua = coroutine.create( function()
    local retValLua = fibLua_lua.fib_Lua(fibNum)
    print("fibonacci corFibLua: " .. retValLua)
end)

while not finished do
    coroutine.resume(_corFibFiber)
    coroutine.resume(_corFibYieldK)
    coroutine.resume(_corFibLua)
end

coroutine.close(_corFibFiber)
coroutine.close(_corFibYieldK)
coroutine.close(_corFibLua)
print("finished")