I've heard that coroutines are one of the most powerful tools to use in scripts. I've read a lot about them on the wiki and lua.org's entry on it. I have a basic understanding of how to create them, but why should I use them?
I've read that you can use them to run 2 loops at the same time, but can't I just create 2 loops in 2 different scripts, and then run them both at the same time?
What's so significant about coroutines?
In general, multithreading is a bad idea, because it introduces races between which threads interact with data in what order. They can provide a performance increase, but only when engineered wisely (and not in Lua -- an implementation detail)
In short, you probably shouldn't use them.
A race condition is when the result of a computation depends on the sequence of certain events. When you introduce multiple coroutines/threads, it's pretty easy to write code that, if it isn't careful/clever enough, will not always act correctly if things get out of sync just slightly (which in practice, they will)
This makes understanding the code much more complicated, because there is no longer any guarantee about the order that code will execute, that variables don't change in confusing ways from multiple threads/coroutines interacting, etc.
Lua significantly alleviates much of this by coroutines over threads, but it's still possible cause race conditions.
Nonetheless, they are often convenient. For instance, in your example, each Script object is given its own coroutine (thread), which is why having multiple scripts acts that way.
Multiple Scripts, however, cannot share variables (which is good and bad). Overall, it decouples the threads from each other, even in just understanding the code.
Using a single script is much cleaner than using many scripts, in case you want to make changes to one of them, for example, or to guarantee that they are all starting at more or less the same time.
A more complicated example https://scriptinghelpers.org/questions/11836/can-one-script-run-many-items for more complicated comparison of with coroutine and without
The second example illustrates that using multiple coroutines can create much simpler appearing code, and in some cases, it truly is simpler. Of course, it's also never necessary to use multiple threads, and in more complicated cases, they could make things much less straightforward.
Definitely other answerers can disagree with my notion that threading is usually not a good choice. This isn't a universal stance for sure (though many believe multithreading should be left to only the people who truly understand multithreading -- Lua doesn't implement true threads and is always "threadsafe" but you can still cause data-races in poorly designed code) so if someone wants to argue for good uses of coroutines they should post an answer!
This post has been significantly edited since first posting -- now I'm more or less happy with the result