On 2023年9月19日 10:24:07 +0100 Marcus Mason <m4gicks@gmail.com> wrote: > >Use case is implementing something like an effect system for Lua, see > ><https://koka-lang.github.io/koka/doc/book.html> where causing an > >effect is implemented by yielding in Lua. > > The general pattern I think for this is to yield a tagged value to request > an effect be performed. You might expose a function called "perform(...)" > which performs such a yield. You can then implement a closer in terms of > this higher level function and it should just work: tm: My current solution is to not use "coroutine.close" but instead do "coroutine.resume(early_return)" to close the coroutine. In this context, "early_return" is a special marker that causes a "perform" function, which you mentioned, to initiate a stack unwinding by invoking "error(early_return)". local function catch_early_return(...) if ... == early_return then error(early_return) else return ... end end function perform(...) return catch_early_return(coroutine.yield(...)) end See also attached "cantyield2.lua" file, which solves the issue (but requires resuming the coroutine during the cleanup process, as Gé Weijers already suggested). So instead of calling "coroutine.close", I do a "coroutine.resume(early_return)". Inside the coroutine, I use an "xpcall" to ensure that the coroutine's stack is unwound on errors (including the "early return" error), such that all __close metamethods run without needing to use "coroutine.close". A tricky issue is to keep track of all involved call stacks for debugging purposes (including nested coroutines), which is what I'm still working on. Regards, Jan
Attachment:
cantyield2.lua
Description: Binary data