Why do people hate Coroutines?

Today, I was arguing with my CTO if we could implement a “Coroutine manager” in our project.
The end result was that he “won”.
He does have a point : The only person who uses Coroutines is me in the studio. He doesn’t want to expose too much stuff with coroutines so it may confuse other people. He said he is OK with me using coroutines as long as I encapsulate them so other people can’t use them.
I understand that he is just doing his job and I think he was just trying to make sure things are smoother.

But I do get a lil sense of hate toward coroutines in unity.
Let me start with that I personally don’t abuse Coroutines, and I use them for an action that only last certain amount of time, or use them to replace simple state machine. It makes the code much shorter, “readable” and very close to human logic.

However, I found that many more senior co-workers really hate coroutines, including my Leader programmer here( they are good programmers and I respect that, they also worked on some big console game projects ).

Most senior people I have worked with came from C/C++ background, and I understand Enumerator is not part of standard C/C++. But come on, Enumerator is one of the key features in C#.

So, why do you guys think many people hate coroutines in Unity?

2 Likes

I think Coroutines are awesome, but as a project manager I would hate them too, unless I really trusted my team (and all of my team felt comfortable with them). Too prone to mess things up if not used correctly (like generating useless GC allocations or people forgetting to correctly clear them).

One point against Coroutines is that if they are interrupted, they cannot be resumed. If you implement a state machine by using conditions in Update(), you can save the conditions and return to that state at any time - not possible to resume any particular spot with Coroutines. Similarly, if a GameObject is disabled, the coroutine is interrupted and cannot be resumed.

Some issues scale upward with project complexity. If, for example, I create a script that uses coroutines and at one point must call StopAllCoroutines, it’ll work fine. But in the future I basically am unable to ever use a coroutine on that component again. (Sometimes StopAllCoroutines is the only option; using StopCoroutine(string) is only possible if the coroutine was called with StartCoroutine(string), which does not allow you to send the coroutine any parameters.)

Despite these, I do use coroutines in small, simple, controlled doses - usually for simple fleeting graphic flourishes and the like, or occasionally for splitting initialization processing across multiple frames, that sort of thing. But it’s really easy to slowly slide into overusing them, and I totally understand outright banning them in a team setting.

2 Likes

HSMs solve the same problem, and they’re arguably simpler to work with. But I guess it comes down to personal preference. I will say the coroutine syntax can be awkward sometimes, such as when you want to call a coroutine from another coroutine.

You guys do have a point.

I totally agree that coroutines can be annoying after interrupted.
The reason why I wanted a coroutine manager in the project was that coroutines can still execute while the related script is disabled . ( sort of like running coroutines outside of specific monobehavior. )

As far as complexity, :), I have seen people doing everything in Update loops and it was nightmare to debug that update loop behavior especially with hundred of boolean checks( bad code , I know ). And I know doing all the continuous behavior in a update loop isn’t a good idea.

In contrast, many short lived behavior in update loop can be a coroutine and it would make things a lot easier to read and debug, such as lerping, wait a second/ a couple frame, Wait until an action is done, etc.

@Demigiant I have never benchmarked the performance of coroutine, but I have read from Unity manual that “Coroutines have virtually no performance overhead.”. I know that coroutines in unity is based on enumeration, so it should probably allocate a enumerator when we start a coroutine. I don’t know If I should trust Unity or not in this case.

I love Coroutines, and uses them a lot in my project - however we are only two programmers and we trust each other 100% :smile:

I do however understand your CTO’s point of view, but having everything in Update can also be a big mess and Coroutines can in different cases come out on top performance wise compared to checking for things in Update, it really depends on the project and situation.

But watch them and watch your GC if your are going the Coroutine way :smile:

Those people who hate coroutines are the same ones who advocate countless “magic” global(public) static variables, because its easier. Wake up people, C# is not C++ !

Things have changed:
http://docs.unity3d.com/ScriptReference/MonoBehaviour.StopCoroutine.html

1 Like

People are afraid of change. I didn’t like them much when I first heard of them, I had to saw more and more examples to finally realize their potential.

It has to do with pride too (“my way works, I don’t need them”).

1 Like

Disclaimer: I’m not a programmer, but I really enjoy coroutines. At the moment, I only use them for timing control. E.g. I want one click to call 3 methods with a short delay between each of them. Much easier than running/maintaining a running timer. Perhaps there is a way around that without coroutines, but I ain’t no programmer :wink:

Still says: “Please note that only StartCoroutine using a string method name can be stopped using StopCoroutine.”

OTOH it does have a version of the method for the non-string version. So maybe they just never changed that line in the docs. In which case… does inaccurate documentation count as a strike against coroutines?

People hate coroutines? Heck I reimplemented them so I could use 'em on a server!

Is it just coroutines, or there a whole range of ‘advanced’ language constructs that they dislike? Do they have a reason (e.g. GC allocations?)

Well… Most of people I know who hate them was because 1) things aren’t done in a traditional way( ie. not done in a update loop ) 2). syntax takes time to get used to.

None of the people I know hate it because of memory usage.

Then it’s just the way they like doing things. I take the opposite approach where I understand a lot of the syntax and various concepts (and there’s a lot) and in return write code that can be half or a quarter the size what other developers might write. For me that just makes sense.

I think coroutines are great. It’s wonderful to be able to simply yield to another coroutine to create a queue of actions. For example, I can spawn a tutorial tip that, on start, yields to a tweening animation, then when that is complete yields until its target is enabled, then yields to an exit tween, and when that is over spawns the next tutorial tip. I could maybe do something similar with events, but in Update it would be a crappy series of conditionals with return statements embedded.

It’s also nice to have a variety of looping methods named after the function they are performing. And, to be honest, being able to wait for a frame or for a set duration is invaluable, especially with animation. In Mecanim, if I set a parameter, I need to wait a frame until it affects the state machine; that’s easy in a coroutine.

1 Like

What’s become of those coders? Didn’t they become programmers because of exactly that? Learning new things, being excited about what a computer/technology can do, etc. etc.? Where’s their pride as a programmer? :smile:

As far as I know this was introduced with 4.5. I haven’t used it yet. To me it looks as that should work:

Corutoine coroutine = StartCoroutine (CoroutineMethod (someArguments));
StopCoroutine (coroutine);

But I don’t submit bug reports for things I haven’t tried. I haven’t because I made my own implementation where this is possible.

Regarding the topic, I indeed hate(d) coroutines, because they are extremely restrictive. They are great, but at the same time it didn’t feel like one has the complete control. It wasn’t even possible to stop a certain coroutine. When I finished my own implementation, I got the control I needed and was very happy again even with more advanced use cases.

There also is a thing called “technical masturbation” - trying to use the most advanced methods and showing off your leet skills just because you can. I don’t think that applies to coroutines, though.

The problem I have with coroutines is that I consider them a “code smell”, an indication that something was solved in a lazy or inflexible way and could be done better. Whenver a Unity coroutine is used, for example, it’s usually a hard-coded sequence of events that should rather be represented as a list of actions (for which you can then write visual editors, too). Coroutines also make unit testing that much harder. That it’s impossible to save their state has been mentioned, too, I think.

1 Like

Should? Why?

I couldn’t disagree more. If I am e.g. having a simple UI animation where a button needs to be moved from one position to another, it is extremely handy to use a coroutine. You may e.g. call myButton.MoveTo (newPosition, 0.2f), the button itself starts a coroutine an moves to that position. At any point, even if the button is moving, we may call myButton.ChangeColor (newColor, 1.0f) which starts another coroutine and changes the color within one second. Even if it is an artificial case, it is one that would be pretty complex to implement without coroutines.

You have to use everything appropriately. If the coroutines can’t be tested, but it is needed in your use case, don’t use them for the unit tests. If you can use integration tests instead, perfect. If it is essential to save the state of a coroutine, there are mostly quite elegant ways to do it. If you want a configurable sequence of actions within the coroutine, set it up in a way it works.

1 Like