lua-async-await
lua-async-await copied to clipboard
Async functions with arguments do not work (parameters are ignored)
Simple example:
local do_thing = a.sync(function (val)
local o = 10
return o + val
end)
print(do_thing(5))
This should print 15, but instead it results in an error at line 3: attempt to perform arithmetic on a nil value (local 'val').
It seems like the library didn't pass the value 5 to the function.
Even in the preview from the README, it's not clear to me how parameters should work. For example:
local a = require "async"
local do_thing = a.sync(function (val)
local o = a.wait(async_func())
return o + val
end)
local main = a.sync(function ()
local thing = a.wait(do_thing()) -- composable!
local x = a.wait(async_func())
local y, z = a.wait_all{async_func(), async_func()}
end)
main()
The function do_thing takes a parameter val. However, the function is called without it, with do_thing(). So, how is the parameter supposed to be used?
Found a solution:
local async = function (fn)
return function (...)
local args = {...}
return function (cb)
assert(type(fn) == "function", "type error :: expected func")
local thread = co.create(fn)
local step = nil
step = function (...)
local stat, ret = co.resume(thread, ...)
assert(stat, ret)
if co.status(thread) == "dead" then
return (cb or function (r) return r end)(ret) -- Added a return
else
assert(type(ret) == "function", "type error :: expected func")
return ret(step) -- Added a return
end
end
return step(table.unpack(args)) -- We pass the arguments here
end
end
end
The main disadvantage, is that now "bare" async functions have to be called two times to startup:
local async_fn = a.sync(function(a,b,c)
print(a,b,c)
end)
local async_fn2 = a.sync(function()
await(async_fn(1,2,3))
await(async_fn(4,5,6))
await(async_fn(7,8,9))
end)
async_fn2()() -- Note the double call
-- Prints:
-- "
-- 1 2 3
-- 4 5 6
-- 7 8 9
-- "
local do_thing = a.sync(function (val)
local o = 10
return o + val
end)
print(do_thing(5)()) -- Note the double call
-- Prints "15"
I made another approach with little change to pong.
Usage:
local task = function(...) -- define task function body first
print(...)
--or some `a.wait` here
end
local a_task = a.sync(task, "params", 233) -- build the thunk (pong) with params
a_task(<callback func>) -- run
--- OUTPUT
-- params 233
Modifies:
local pong = function (func, ...) -- `wrap` unpacked the params from sync(...), so we need pickout real `<callback func>` from them
assert(type(func) == "function", "type error :: expected func")
-- do the pick
local params = {...}
local callback = table.remove(params)
local thread = co.create(func)
local step = nil
step = function (...)
local stat, ret = co.resume(thread, ...)
assert(stat, ret)
if co.status(thread) == "dead" then
(callback or function () end)(ret)
else
assert(type(ret) == "function", "type error :: expected func")
ret(step)
end
end
step(table.unpack(params)) -- params here for coroutine entrance
end
@timrockefeller I get an error trying to call it:
local task = function(...) -- define task function body first
print(...)
--or some `a.wait` here
end
local a_task = a.sync(task, "params", 233) -- build the thunk (pong) with params
a_task()
This yields:
lua: test.lua:23: attempt to call a number value
stack traceback:
test.lua:23: in local 'step'
test.lua:29: in function <test.lua:9>
(...tail calls...)
test.lua:94: in main chunk
[C]: in ?
However, you can fix that by adding a nil check to wrap:
local wrap = function (func)
assert(type(func) == "function", "type error :: expected func")
local factory = function (...)
local params = {...}
local thunk = function (step)
if not step then -- check nil here
step = function (...) end
end
table.insert(params, step)
return func(table.unpack(params))
end
return thunk
end
return factory
end
Still, await doesn't seem to work as expected. Running:
local f = a.sync(function(arg1, arg2, arg3)
print('arg1: ' .. arg1)
print('arg2: ' .. arg2)
print('arg3: ' .. arg3)
end)
local g = async(function()
a.wait(f('arg1', 'arg2', 'arg3'))
a.wait(f('arg1', 'arg2', 'arg3'))
a.wait(f('arg1', 'arg2', 'arg3'))
end)
g()
Yields an error: lua: attempt to concatenate a nil value (local 'arg1')
I fixed it by switching to luajls See #10.