As a Roblox developer, it is currently too hard to spawn threads with error handling and
delay cannot take additional arguments.
If Roblox is able to address this issue, it would improve my development experience because it would allow me to cleanly spawn a function with arguments but still get proper error handling.
delay doesn’t accept additional arguments
coroutine.resume eats errors
xpcall allows you to get the correct stack trace but can’t be outputted correctly
Ideally I would want to have full control over the arguments given to whatever thread I am spawning without making it impossible to get proper error messages.
There are a bunch of potential solutions I can come up with. #6 is the most general and most useful one and is the one I would prefer personally.
- Add an option or direct alternative to
coroutine.resumethat doesn’t eat errors (Not a clean solution but decent)
- Stop eating errors from
coroutine.resume(Might be annoying, and could cause lag due to error spam)
- Pass extra arguments to
resume(Doesn’t fix most issues, keeps two useless arguments)
- Add an option or direct alternative to them that lets you overrride arguments (Not a clean solution)
- Add a new way to spawn threads or functions with the two core problems solved (Fixes most of the problems just fine)
- Add a way to output “fake” errors (e.g. as
debug.error) or allow
errorto take threads too. (Fixes all the issues, generalized, adds new uses, but most complex)
It could accept a level/thread, just like how
error accepts a level, but wouldn’t kill the caller.
local success, err = coroutine.resume(thread, ...) if not success then debug.error(err, thread) -- Outputs the error like it came from the thread end
This would also allow you to still return the results assuming the body doesn’t yield which could be very useful.
(P.s. you can prove that threads remember the error location with the new
debug.info function by passing the thread, a
1 for the first level, and then
"l" to get the current line number of the thread)
Here are some of the examples of why this would be useful.
This eliminates ever having to do error handling and hackily outputting the error with
xpcall which is bulky.
If you’re utilizing LogService in order to collect errors in your games you don’t need extra code paths for the above
Makes it possible to jump to correct locations by clicking the stack.
Having cleaner errors when spawning threads makes this a lot easier to debug:
-- Assuming #6 this is how you could define betterSpawn (you could assume #5 just replaces this): local function betterSpawn(func, ...) local thread = coroutine.create(func) local success, err = coroutine.resume(thread, ...) if not success then debug.error(err, thread) -- Would output the error perfectly (But execution continues below) end return success, err end local function addChild(child) -- Stuff end -- I use this pattern a lot for things like Players:GetPlayers() and Players.PlayerAdded especially for _, child in ipairs(something:GetChildren()) do betterSpawn(addChild, child) -- Spawn it with one of the solutions end something.ChildAdded:Connect(addChild)
Assuming you can output custom errors like in #6 you could use this for better debugging in general.
It would also make reverse engineering obfuscated code easier with tools, meaning exploit scripts can be patched faster by developers. This is really useful with
loadstring and/or for spawning “fake” scripts like in my prototype script sandboxing tool (Which is designed to fit a use case like this)