I felt like mentioning that using coroutine.resume
in a module can break anything that requires
, couldn’t find it elsewhere.
If you’re wondering what I’m refering to, trying to require this module will cause your script to yield indefinitely.
local co = coroutine.running()
task.defer(function()
coroutine.resume(co)
end)
coroutine.yield()
return "meow"
First of all, we should figure out how require
works, when you require a ModuleScript
object in Roblox, it creates a new thread to run that module in, or, in a theoretical Lua sense, it would be this
local function require(module)
local f = debug.loadmodule(module)
local thread = coroutine.create(f)
return require_arg_capture(module, coroutine.resume(thread)) -- imagine this does the return caching or whatever, its not relevent here
end
If you understand how coroutines work, you might already see the issue here. But for those who don’t let me explain how yield
/resume
work.
When a thread is resumed, the thread that called coroutine.resume
is marked as the thread that gets the response when you return or yield (completing as I like to call it), when require
is called, its assumed this will be the script that required it.
However, because we resume in a task.defer
block, require
loses its response expectation and will never receive it.
If you add a print here…
task.defer(function()
print(coroutine.resume(co))
end)
You’ll notice the MEOW
goes here, and not the script calling require
. The require
will never get the meow
because when a thread returns, it’s killed and will never resume again.
So why doesn’t this happen with task.spawn, simple, it doesn’t want a response. Because of this, the require
is still treated as the thread that’ll get the response.
In summary, using coroutine.resume
can cause require to break because of how coroutines handle their responses.