Coroutine.Create() V.S. Couroutine.Wrap()

So I’ve been learning couroutines and I don’t know what the difference is between coroutine.create() and coroutine.wrap(). I’ve hard that couroutine.wrap() can be used to wrap functions coroutine.wrap(functionname) but you can do the same thing with coroutine.create(functionname) .

3 Likes

coroutine.create(f) actually creates a new instance of a thread, from where you can use coroutine.resume(thr) to resume that thread. Similar to pcall, coroutine.resume returns a boolean indicating that the function was called successfully, and then anything else returned by the passed function, otherwise if there was an exception, the error message as a string.

coroutine.wrap(f) on the other hand just returns a “coroutine’d” version of f, so that when you call it the wrapped function is called in its own thread basically. With coroutine.create + resume you can get more control over exception handling, although coroutine.wrap is usually easier to use.

16 Likes

So for couroutine.wrap you don’t have to use couroutine.resume? and what is exception handling? also you said couroutine.create() is similar to pcall and by that do you mean pcall functions create a seperate threread?
And Also, your saying basically coroutine.create creates a new thread while coroutine.wrap runs on a seperate thread??

I think your explanation on coroutine.wrap is a little bit finnicky, so I’ll try my best to expand upon what you’ve said.

coroutine.wrap returns a function that when called, basically calls coroutine.resume(thread). The primary difference is that you cannot use your generic coroutine functions (excluding coroutine.create, since it returns a function). That’s the primary difference between using coroutine.wrap and coroutine.create that many people fail to understand.

Hopefully I didn’t explain anything wrong, and again, hopefully I captured what you were trying to say.


A big bad with Coroutines is that sometimes they can just… void your stack trace. Like, all of it. Gone. I don’t know the internals as to why that happens, and it seems to be an issue in other languages as well, but it’s something you should look out for when debugging especially when using coroutines. Another funny thing that happens is that if you use a coroutine and it errors, it’ll lead you to where the coroutine was resumed, however it won’t give you the exact line where the error happened. Happy debugging!


Also, here’s a piece of trivia. Did you know that the return value for coroutine.wrap says that it returns a Thread object, however it actually returns a function (and even doubles down on that in it’s description?) How quaint.

12 Likes

Correct. Instead you call the returned function.

function myFunc()
    print('hi')
end

local wrapped = coroutine.wrap(myFunc)

-- When you want it to run,
wrapped()

Dealing with errors gracefully, in the same way you’d use pcall to protect a call and then perform different actions based on whether it succeeded or failed.

For example if you did a DataStore call and it errored, you’d want to know so you can retry the call. Wrapping a function doesn’t give you that information, but creating and resuming a thread does.


No, the similarity incapaz was referring to was the exception handling - the return of a Boolean + error message or returned parameters.

Pcall runs in the current thread. Coroutines create a new thread. They are not interchangeable.


coroutine.wrap returns a function like this:

function wrapped(...)
    coroutine.resume(coroutine.create(yourFunc), ...)
end

-- Calling wrapped() is equivalent to doing:
coroutine.wrap(yourFunc)()

So each time you call the wrapped function you get another new thread that it runs in. It is a wrapper for the other methods, but you effectively run it blind by doing this hence all the points about exception handling.

14 Likes

Ok so I think I get it but I have one more question which is what hapens to a coroutine after it runs

It dies and you can’t use coroutine.resume() or call it again without creating a new one.