Hello developers, today I think I found a bug. I was working on a project when I added a certain snippet of code that locked everything. After a lot of debugging, I was able to narrow down the problem to coroutine.yield, and I separated the code into a separate script to test it without any interference. These are the two scripts in their entirety:
Script:
local result = require(script.Parent:WaitForChild("ModuleScript"));
print(result); --This does not print.
ModuleScript:
local thread = coroutine.running();
task.spawn(function()
task.wait(1);
coroutine.resume(thread);
end);
coroutine.yield();
return "Why doesn't this return?", print("This is printing, for some reason"); --This does print, I am only adding the print here for testing reasons
As you can see this is a simple test, there is a separate task that waits one second, to then resume the paused coroutine. Normally, someone would assume that the problem is before the return statement. But the This is printing, for some reason message prints to the console, which gives us the knowledge that the return statement is running. For some reason, the script never receives the result, and as such, halts its entire execution.
Does someone know why, or if this is a bug?
Edit: For those wondering why I couldn’t just ditch task.spawn entirely and use task.delay, it’s because inside task.spawn there is code running that doesn’t allow me to just replace everything.
coroutine.yield doesn’t accept a thread to be yielded, only arguments that will be passed the next time you resume the thread. I believe in the print’s case, it’s already being evaluated for the return value which is just going to be void anyway because print doesn’t return anything.
In any case: the task library is also able to resume threads so you can just directly pass the acquired thread from coroutine.running as an argument to task. Additionally, you should use task.delay rather than waiting at the start of a spawned thread, it’ll do the same thing in one function.
local thread = coroutine.running()
task.delay(1, thread)
coroutine.yield()
return "This returns"
Thank you for pointing out the mistake in courotine.yield, I forgot it didn’t need an argument. (for those wondering the reason it didn’t have an impact is that courotine.yield thought the thread was a message).
In case of the print, the reason I added it to the return message is precisely for what you said. If it is evaluated for the return and it prints, then that means the return keyword is running. So I only added it there to test that.
In regard to task.delay, the reason I can’t use task.delay is because in my actual script (the one I took this error from), there is code executing between coroutine.resume and coroutine.yield. To be more precise it is a promise, so that’s why I can’t use task.delay for the actual use case. However, you are completely right about using it for this example.
For those wondering, based on @colbert2677 answer and linked post, I came up with this solution:
local thread = coroutine.running();
task.spawn(function()
task.wait(1);
--Let's assume some stuff goes here.
if (coroutine.status(thread) == "suspended") then --Add this to prevent errors (if the coroutine is still running, then it will spawn twice and cause things to mess up)
task.spawn(thread);
end
end);
coroutine.yield();
return "This is working.", print("This is printing as well");
Just by replacing coroutine.resume with task.spawn the script functions normally.