Beginners Guide to Coroutines: Difference between revisions

From Legacy Roblox Wiki
Jump to navigationJump to search
>MrNicNac
New page: == What is a coroutine? == Coroutines are some of the most interesting, useful parts of lua yet still some of the most misunderstood. When you make a new coroutine, it will create a new ''...
Adding ScriptTutorial template
 
(65 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{ScriptTutorial|easy|scripting}}
== What is a coroutine? ==
== What is a coroutine? ==
Coroutines are some of the most interesting, useful parts of lua yet still some of the most misunderstood. When you make a new coroutine, it will create a new '''thread''' which is sort of like adding a new script to your place.
Coroutines are some of the most interesting, useful parts of lua yet still some of the most misunderstood. When you make a new coroutine, it will create a new '''thread''' which is sort of like adding a new script to your place. Be careful though, too many threads mean a lot of lag!


== How to create a coroutine ==
== How to create a coroutine ==
Creating a coroutine is fairly simple, all you need to start is a function and ''coroutine.create()''. The one parameter of coroutine.create will be the function you wish to run, so like this.
Creating a coroutine is fairly simple, all you need to start is a function and ''coroutine.create()''. The one parameter of coroutine.create will be the function you wish to run, so like this.


function core()
<syntaxhighlight lang="lua">
    print("hola")
local newThread = coroutine.create(function()
end
    print("hola")
end)
new_thread=coroutine.create(core)
</syntaxhighlight>
 
Now you've created your first coroutine and started a new thread! Yet nothing has happened, well this is because you haven't run it. To run your coroutine you will need to use ''coroutine.resume()'' and the parameter will be the thread you created.


Now you've created your first coroutine and started a new thread! Yet nothings happening, well this is because you haven't run it. To run your coroutine you will need to use ''coroutine.resume()'' and the parameter will be the thread you created
{{code and output|code =
local newThread = coroutine.create(function()
    print("hola")
end)


function core()
coroutine.resume(newThread)
    print("hola")
|output=hola}}
end
new_thread=coroutine.create(core)
coroutine.resume(new_thread)


Now in your output you should see "hola" Now lets say you wanted to call parameters in your coroutine's function, well you will do that with ''coroutine.resume()'' like so
Let's say you wanted to call parameters in your coroutine's function, well then what you will need to do that with is ''coroutine.resume()'' like so


function core(a,b,c)
{{code and output|code =
    print(a*b+c)
local newThread = coroutine.create(function(a, b, c)
end
    print(a*b + c)
end)
new_thread=coroutine.create(core)
coroutine.resume(new_thread,3,5,6)


Now you should see "21" in the output because 3*5+6 is 21.
coroutine.resume(newThread, 3, 5, 6)
|output = 21}}


== coroutine.wrap ==
== coroutine.wrap ==
''coroutine.wrap()'' can be used in a way, as a replacement for ''coroutine.resume'' and ''coroutine.create''. You use ''coroutine.wrap'' on the function like ''coroutine.create'' but you will use the variable you asign it to like a function. Think of ''coroutine.wrap'' as a function with a coroutine shoved inside it.
''coroutine.wrap()'' can be used as a replacement for ''coroutine.resume'' and ''coroutine.create''. You use ''coroutine.wrap'' on the function like ''coroutine.create'' but you will use the variable you assign it to like a function. Think of ''coroutine.wrap'' as a function with a coroutine shoved inside it.
 
{{code and output|code =
local newThread = coroutine.wrap(function()
    print("Hola")
end)
 
newThread()
|output = Hola}}


function core()
If you want to add in parameters, just do it like you would any other function.
    print("Hola")
end
new_thread=coroutine.wrap(core)
new_thread()


This will print "Hola" into the output. If you want to add in parameters, just do it like you would any other function.
{{code and output|code =
local newThread = coroutine.wrap(function core(a,b,c)
    print(a*b+c)
end)


function core(a,b,c)
newThread (8,2,1)
    print(a*b+c
|output=17}}
end
new_thread=coroutine.wrap(core)
new_thread(8,2,1)


This will print "17" into the output because 8*2+1 is 17.


== What are coroutines really useful for? ==
== What are coroutines really useful for? ==
You have learned acouple of the coroutine functions, but what can you use them for? Well one of the most useful things, is making loops and functions run at the same time. For example :
You have learned a couple of the coroutine functions, but what can you use them for? Well one of the most useful things is making loops and functions run at the same time.
 
<syntaxhighlight lang="lua">
local h = Instance.new("Hint", workspace);
local m = Instance.new("Message", workspace);
 
local changeHint = coroutine.wrap(function()
    for i = 60, 0, -1 do
      wait(0.5)
      h.Text = i
    end
end)
local changeMessage = coroutine.wrap(function()
    for i = 60, 0, -1 do
        wait(1)
        m.Text = i
    end
end)


local h=Instance.new("Hint",workspace);
changeHint()
local m=Instance.new("Message",workspace);
changeMessage()
</syntaxhighlight>


coroutine.resume(coroutine.create(function()
As you can now see, the message and the hint both change their text at the same time, but at different speeds.
for i=60,0,-1 do
Wait(0.5)
h.Text=i
end end -- one for the for, one for the function
)--closes create
)--closes resume


for i=60,0,-1 do
Also, coroutine.resume will return error information, like [[pcall]]. ''coroutine.resume()'' will return a boolean, saying if it suceeded, and if it didn't, then a string which is the error message.
Wait(1)
m.Text=i
end


and as you can now see, the message and the hint both change their text at the same time but at different speeds, however, they could be the same speed but for example purposes, they weren't.
{{code and output|code =
local success, errorMessage = coroutine.resume(coroutine.create(function()
    ppprint("HI")
end))
 
if not success then -- check if there is an error
    print("There was an error:", errorMessage)
end
|output =
There was an error: Script:2: attempt to call global 'ppprint' (a nil value)
}}


== more, more coroutines ==
== more, more coroutines ==
Line 81: Line 98:
''coroutine.yield'' puts your coroutine in suspended mode, where it just stops and waits until the coroutine is called again. ''coroutine.yield'' cannot include a metamethod, C function or an iterator. ( if you don't know what those are then you're most likely not using them. ) Anything extra put inside a ''coroutine.yield'' will go straight to ''coroutine.resume''.
''coroutine.yield'' puts your coroutine in suspended mode, where it just stops and waits until the coroutine is called again. ''coroutine.yield'' cannot include a metamethod, C function or an iterator. ( if you don't know what those are then you're most likely not using them. ) Anything extra put inside a ''coroutine.yield'' will go straight to ''coroutine.resume''.


function core(param)
{{code and output|code =  
  print (param)
  stuff_will_be_here=coroutine.yield()
  print ("yield : " .. stuff_will_be_here)
end
new_thread=coroutine.wrap(core)
new_thread("Hola mi amigos!")
new_thread("This was in yield :O")


This will print<br>
Hola mi amigos!<br>
yield : This was in yield :O<br>


=== coroutine.status ===
new_thread=coroutine.wrap(function(param)
''coroutine.status'' will tell you if your coroutine is either dead, suspended,running or normal. It will return this as a string to you. What do those mean?
  print(param)
  local resumedWith = coroutine.yield()
  print("Resumed with: " .. resumedWith)
end)
new_thread("Hola mis amigos!")
new_thread("This was retrieved with yield()")
|output =
Hola mis amigos!
Resumed with: This was retrieved with yield()
}}
 
 
=== coroutine.status() ===
''coroutine.status()'' will tell you if your coroutine is either dead, suspended, running or normal. It will return this as a string to you. What do those mean?
*running means that the coroutine is currently working and using its code.
*running means that the coroutine is currently working and using its code.
*dead means that the coroutine has stopped running and is done for now.
*dead means that the coroutine has stopped running and is done for now.
Line 103: Line 122:
Now how do we use it? We simply do
Now how do we use it? We simply do


function core()
{{code and output|code =
    print("hola")
function core()
end
    print("hola")
end
new_thread=coroutine.create(core)
 
new_thread=coroutine.create(core)


print(coroutine.status(new_thread))
print(coroutine.status(new_thread))


coroutine.resume(new_thread)
coroutine.resume(new_thread)


print(coroutine.status(new_thread))
print(coroutine.status(new_thread))
|output =
suspended
hola
dead
}}


This will print <br>
suspended<br>
hola<br>
dead<br>
in the output.
=== coroutine.running() ===
=== coroutine.running() ===
''coroutine.running()'' will return the current thread running. Example
''coroutine.running()'' will return the current thread that is running. Example:


new_thread=coroutine.create(function()
{{code and output|code =
    print("hola")
new_thread=coroutine.create(function()
end)
  print("hola")
end)
print(coroutine.running())
 
print(coroutine.running())
| output =
A hexadecimal memory location where the coroutine is stored. (i.e. thread: 183E0548)
}}
 
== See Also ==
*[[Function_Dump/Coroutine Manipulation|Coroutine Manipulation]]
*[http://www.lua.org/pil/9.html Programming in Lua: Coroutines]
*[http://www.lua.org/manual/5.1/manual.html#2.11 Lua 5.1 Reference Manual: Coroutines]
*[http://www.lua.org/manual/5.1/manual.html#5.2 Lua 5.1 Reference Manual: Coroutine Manipulation]


This will put something like : thread: 183E0548 in the output.
[[Category:Scripting Tutorials]]

Latest revision as of 21:30, 28 April 2023

This is an easy, scripting related tutorial.

What is a coroutine?

Coroutines are some of the most interesting, useful parts of lua yet still some of the most misunderstood. When you make a new coroutine, it will create a new thread which is sort of like adding a new script to your place. Be careful though, too many threads mean a lot of lag!

How to create a coroutine

Creating a coroutine is fairly simple, all you need to start is a function and coroutine.create(). The one parameter of coroutine.create will be the function you wish to run, so like this.

local newThread = coroutine.create(function()
    print("hola")
end)

Now you've created your first coroutine and started a new thread! Yet nothing has happened, well this is because you haven't run it. To run your coroutine you will need to use coroutine.resume() and the parameter will be the thread you created.

local newThread = coroutine.create(function()
    print("hola")
end)

coroutine.resume(newThread)
hola

Let's say you wanted to call parameters in your coroutine's function, well then what you will need to do that with is coroutine.resume() like so

local newThread = coroutine.create(function(a, b, c)
    print(a*b + c)
end)

coroutine.resume(newThread, 3, 5, 6)
21

coroutine.wrap

coroutine.wrap() can be used as a replacement for coroutine.resume and coroutine.create. You use coroutine.wrap on the function like coroutine.create but you will use the variable you assign it to like a function. Think of coroutine.wrap as a function with a coroutine shoved inside it.

local newThread = coroutine.wrap(function()
    print("Hola")
end)

newThread()
Hola

If you want to add in parameters, just do it like you would any other function.

local newThread = coroutine.wrap(function core(a,b,c)
    print(a*b+c)
end)

newThread (8,2,1)
17


What are coroutines really useful for?

You have learned a couple of the coroutine functions, but what can you use them for? Well one of the most useful things is making loops and functions run at the same time.

local h = Instance.new("Hint", workspace);
local m = Instance.new("Message", workspace);

local changeHint = coroutine.wrap(function()
    for i = 60, 0, -1 do
       wait(0.5)
       h.Text = i
    end
end)
local changeMessage = coroutine.wrap(function()
    for i = 60, 0, -1 do
        wait(1)
        m.Text = i
    end
end)

changeHint()
changeMessage()

As you can now see, the message and the hint both change their text at the same time, but at different speeds.

Also, coroutine.resume will return error information, like pcall. coroutine.resume() will return a boolean, saying if it suceeded, and if it didn't, then a string which is the error message.

local success, errorMessage = coroutine.resume(coroutine.create(function()
    ppprint("HI")
end))

if not success then -- check if there is an error
    print("There was an error:", errorMessage)
end
There was an error: Script:2: attempt to call global 'ppprint' (a nil value)

more, more coroutines

coroutine.yield

coroutine.yield puts your coroutine in suspended mode, where it just stops and waits until the coroutine is called again. coroutine.yield cannot include a metamethod, C function or an iterator. ( if you don't know what those are then you're most likely not using them. ) Anything extra put inside a coroutine.yield will go straight to coroutine.resume.

new_thread=coroutine.wrap(function(param)
  print(param)
  local resumedWith = coroutine.yield()
  print("Resumed with: " .. resumedWith)
end) 
new_thread("Hola mis amigos!")
new_thread("This was retrieved with yield()")

Hola mis amigos!

Resumed with: This was retrieved with yield()


coroutine.status()

coroutine.status() will tell you if your coroutine is either dead, suspended, running or normal. It will return this as a string to you. What do those mean?

  • running means that the coroutine is currently working and using its code.
  • dead means that the coroutine has stopped running and is done for now.
  • suspended means coroutine.yield() ran and it's waiting to start up again.
  • normal means it hasn't been told to start running yet.

Now how do we use it? We simply do

function core()
    print("hola")
end

new_thread=coroutine.create(core)

print(coroutine.status(new_thread))

coroutine.resume(new_thread)

print(coroutine.status(new_thread))

suspended hola

dead

coroutine.running()

coroutine.running() will return the current thread that is running. Example:

new_thread=coroutine.create(function()
   print("hola")
end)

print(coroutine.running())
A hexadecimal memory location where the coroutine is stored. (i.e. thread: 183E0548)

See Also