[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Jumping out of a function without error semantics
- From: Kevin Martin <kev82@...>
- Date: Mon, 28 Jan 2013 22:16:27 +0000
On 28 Jan 2013, at 20:12, Noah Watkins wrote:
> Our Lua functions look like:
>
> function do_something(context)
> … do stuff …
> if (condition)
> context.abort()
> end
>
> We map context.abort() to lua_error, and all other return paths are an implicit commit/success. We'd like to provide an explicit context.commit() function that never returns, but doesn't necessarily use the lua_error mechanism.
I was playing with something like this the other day. I think it's correct, but I'm still getting to grips with coroutines, so it might not be.
Have a look at the attached code for the transaction function (Lua 5.2 only). You should lua_pcall it, with the function you actually want to call as the first argument. It will return false/true if context.abort() or context.commit() were called. Errors should be handled as normal. The function can yield and will be resumed. There's no support for returning values - although I think this is pretty easy to add. Also, a failure to commit/abort results in an error.
Kev
-----------------------------
function transaction(f, ...)
local args = {...}
local uniqueval = {}
local coroutine = require("coroutine")
local table = require("table")
local cmds = {}
function cmds.abort()
coroutine.yield(uniqueval, false)
end
function cmds.commit()
coroutine.yield(uniqueval, true)
end
local co = coroutine.create(function()
local ok, err = pcall(f, cmds, table.unpack(args))
if ok then err = "You forgot to commit" end
error(err)
end)
::restart_routine::
local yv = {coroutine.resume(co)}
if yv[1] == false then
--There was an error, pass it on
error(yv[2]);
end
--There was no error, it must be a yield
assert(coroutine.status(co) == "suspended");
if yv[2] ~= uniqueval then
--It was another yield
local newvals = coroutine.yield(table.unpack(yv, 2))
goto restart_routine
end
assert(type(yv[3]) == "boolean")
return yv[3]
end