Yield a coroutine?

Hello, I have been wondering for a while and it finally came to an issue. How do you yield coroutines? If I have a wrapped function like this:

coroutine.wrap(function

end)()

How do I yield it? Is there a way for me to wait until a coroutine stopped?

coroutine.yield(). It yields the coroutine/thread in which you run it, and can be resumed again later:
image

coroutine.wrap(function()
    coroutine.yield()
    --This won't run
end)()

Sorry, I should have given more detail. What I mean is to yield in an async enviroment (by async I mean that the coroutine and normal script are running in a separate thread).

So:

local myFunc = coroutine.wrap(function

end);

myFunc();

myFunc:Wait(); --Something like this, it will wait until the coroutine finished

You can use a bindable event:

local stopped = Instance.new("BindableEvent")

coroutine.wrap(function()
    stopped:Fire() --Fire right before yielding
    coroutine.yield()
end)

stopped.Event:Wait() --will wait until the coroutine finished

You can fire that event from the coroutine whenever youā€™d like.

Is there any way without using Instances? Bindable events canā€™t send important arguments like tables with metatables in them. This would break my entire proxy system (Since it is an empty table that is connected to another using a metatable).

Not sure if thereā€™s a way to do it without instances.

But you could store the table variable outside of the coroutine, the coroutine will make changes to it, and then you will have it with the metatables and everything outside of the coroutine, without giving it to the BindableEvent.

local stopped = Instance.new("BindableEvent")
local tab = setmetatable({},{})
coroutine.wrap(function()
    --Make changes to the table
    stopped:Fire() --Fire right before yielding
    coroutine.yield()
end)

stopped.Event:Wait() --will wait until the coroutine finished
--Use tab here

Or the second option, apply the metatables back after the firing.

Thinking you could do something like:

local thisThread = coroutine.running() -- this will return the thread that is being run right now
coroutine.wrap(function()
    -- your stuff
    coroutine.resume(thisThread) -- now resume the thread that is outside of this coroutine
end)()
coroutine.yield() -- now this will yield indefinitely until resumed
2 Likes

Oh. It was that easy? Thank you!

1 Like

Think so, test it out first just to be safe but afaik that should work.

1 Like

Yep, it did work. Thank you!

1 Like

It is preferable to use task.spawn instead of coroutine.wrap/coroutine.create and coroutine.resume because they are notorious with not logging errors that happen in the threads made by coroutine and will make you pluck your hair out trying to figure why your code just doesnā€™t work.

2 Likes

Really? I just got 2 answers in one post! The EventModule was really annoying with this since it needed to spawn the function. It logged like ā€œError in pairs()ā€ instead of the entire thread. Thank you!

Yep, just to make sure you do it right, itā€™s like this:

local thisThread = coroutine.running() -- this will return the thread that is being run right now
task.spawn(function()
     -- your stuff
    task.spawn(thisThread) -- now resume the thread that is outside of this coroutine
end)
coroutine.yield() -- now this will yield indefinitely until resumed

Also, you can resume any thread from any other thread as long as you got the thread id using coroutine.running(), so you can resume thread in script A from script B, which is pretty cool

1 Like

This isnā€™t entirely true, ā€˜coroutineā€™ wrapper functions created via the coroutine.wrap() function are ran in a call stack shared by the active/current thread of execution, any errors that occur in the coroutineā€™s functionā€™s body are propagated to the call to the wrapper function itself, for example.

coroutine.wrap(function()
	print(true + false)
end)()
--attempt to perform arithmetic (add) on boolean

coroutine.resume() on the other hand resumes the execution of coroutines in an alternate call stack (similar to the pcall/xpcall globals) unique to the coroutine itself, this means that errors are not propagated to calls to coroutine.resume().

coroutine.resume(coroutine.create(function()
	print(true + false)
end))
--Error is not propagated.

In the former example the call stack of the active/current thread is terminated, in the latter example an alternate call stack is terminated.

Also, you can resume any thread from any other thread as long as you got the thread id using coroutine.running() , so you can resume thread in script A from script B, which is pretty cool

Just be wary of the fact that coroutines do not cross the network boundary.

1 Like