I’m running a script in a nested coroutine, but if a certain condition occurs, I want to break out of the enclosing coroutine. Is there a way for me to do that?
IEnumerator Enclosing() {
yield return Nested();
Debug.Log("Didn't get a 5!");
}
IEnumerator Nested() {
yield return null;
if (Random.Range(0, 10) == 5) // break out of enclosing
}
This is a simplified form of what I’m doing, but it’s similar enough for illustration purposes. I can’t just combine the two coroutines, because the nested routine is coming from a base class that is extended multiple times.
Is there a way for me to essentially “yield break” out of the enclosing coroutine?
IEnumerator Enclosing() {
var nestedEnumerator = Nested();
if (nestedEnumerator != null)
yield return nestedEnumerator;
Debug.Log("Didn't get a 5!");
}
IEnumerator Nested() {
yield return new WaitForEndOfFrame();
if (Random.Range(0, 10) == 5)
yield return null;
}
However, if that is all you want to achieve - give me a random number except 5 - then you can simplify that logic by a lot. The code fragment you posted does not require nesting the enumerator. It could also be a simple method call from the Enclosing() coroutine.
The given coroutine logic will simply wait for a frame and then check if the random number is 5 or not and then do something with that result. It will however not run this every frame, it will just defer the random decision making to the end of / next frame.
Coroutines don’t have means of communication, so there’s no built-in way to communicate return values or abortion between them.
There’s a few ways around this but they’re all not very pretty:
Pass something into the Nested coroutine that communicates to the outside. This could be a CancellationTokenSource or a delegate that sets a local variable of the Enclosing routine. Then, when the Nested routine completes, the Enclosing routine can check the token / value.
Enumerate the Nested routine manually, i.e. using foreach on the nestedEnumerator. Then the Enclosing routine can check the yielded value and either yield return it itself to Unity or act on it in some special way.
But you might also want to look at async methods. They work pretty well in recent versions of Unity and you can use UniTask to make working with them easier. With async methods, you can return a value or raise an exception directly and the enclsoing async method then can act on it.
@CodeSmile I don’t get your example. For one, a generator method will never return null. You’ll always get an IEnumerator instance, the null check in Enclosing is pointless. Also, the log message “Didn’t get a 5!” will always be executed, irrespective of the Nested routine getting a random value of 5 or not.
Outside of prototyping and some very specific usecases, i would recommend to try and stay away from Coroutines. For anything simple, you may aswell just write your own code. For anything more complex, coroutines simply take away your control over the code execution and make working with it more annoying (and usually less clear).
Without knowing the actual usecase we cant comment on more specific solutions.
Given only the example and the abstract question, i think those have been addressed.
Thanks for correcting! I think Nested should have just returned that instance rather than yield it, that ought to work. Which means it‘s no different than any regular method call to begin with and wouldn‘t be a nested coroutine.