Nested coroutines

I have one routine, `Func1` which returns an `IEnumerator`. This method is called by another coroutine `Func2` that has been started with `StartCoroutine`. The intent is that `Func2` should wait for the completion of `Func1`.

Ideally, I'd just yield the IEnumerator returned by `Func1` and let the

IEnumerator Func1()
{
    for (int i=0; i<10; i++)
    {
        yield return null;
    }
    yield break;
}

IEnumerator Func2()
{
    //wait for the completion of Func1
    yield return Func1();
}

However, Unity doesn't seem to recursively iterate over IEnumerators, so Func2 yields just once. An alternative is to manually iterate over the IEnumerator,

IEnumerator Func2()
{
    //wait for the completion of Func1
    IEnumerator e = Func1();
    while (e.MoveNext()) yield return e.Current;
}

but I was looking for a less clunky solution, much like the way I can yield a WWW object and wait for its completion?

EDIT: Removed superfluous yield statement in func2. It turns out, that MoveNext should be called before accessing IEnumerator.Current

You want:

IEnumerator Func2()
{
    yield return StartCoroutine( Func1() );
}

`Func2` will not continue execution until the `Func1` coroutine has completed. `StartCoroutine()` returns a `Coroutine` object, and this object can be returned by `yield`. Unity knows to finish executing the new `Coroutine` object before resuming the original function. You can use this technique to chain and nest coroutines.

For example: You want to create an object that does three in this order: fade in, move, and then shoot a gun. But since moving and shooting is very common in this game, you want to have a single function that simple does them both. You could write something like:

public void Start()
{
  // Somebody starts the coroutine chain by calling:
  StartCoroutine( FadeAndMoveAndShoot() );
}

private IEnumerator FadeAndMoveAndShoot()
{
  print( "FadeAndMove Start: " + Time.time );
  yield return StartCoroutine( Fade() );
  print( "FadeAndMove Middle: " + Time.time );
  yield return StartCoroutine( MoveAndShoot() );
  print( "FadeAndMove End: " + Time.time );
}

private IEnumerator Fade()
{
  print( "Fade Start: " + Time.time );
  yield return new WaitForSeconds( 2.0f );
  print( "Fade End: " + Time.time );
}

private IEnumerator MoveAndShoot()
{
  print( "Move Start: " + Time.time );
  yield return new WaitForSeconds( 3.0f );
  print( "Move Middle: " + Time.time );
  yield return StartCoroutine( Shoot() );
  print( "Move End: " + Time.time );
}

private IEnumerator Shoot()
{
  print( "Shoot Start: " + Time.time );
  yield return new WaitForSeconds( 1.0f );
  print( "Shoot End: " + Time.time );
}

This will essentially output:

FadeAndMove Start: 0
  Fade Start: 0
  Fade End: 2
FadeAndMove Middle 2
  Move Start: 2
  Move Middle: 5
    Shoot Start: 5
    Shoot End: 6
  Move End: 6
FadeAndMove End: 6

The numbers are in seconds, and you can see that the original FadeAndMove courtine takes 5 seconds to complete. The desired behavior.

You can do this by "manually" iterating through the 2nd coroutine's IEnumerator object that it returns, like this:

IEnumerator Func2()
{
    Debug.Log("Func2 start");

    // manually iterate over Func1
    IEnumerator f1e = Func1();
    while (f1e.MoveNext()) {
        yield return null;
    }

    Debug.Log("Func2 complete");
}

IEnumerator Func1()
{
    Debug.Log("Func1 start");
    for (int i = 0; i < 10; i++)
    {
        Debug.Log("Func1: " + i);
        yield return null;
    }
    Debug.Log("Func1 complete");
    yield break;
}


Output:

Func2 start
Func1 start
Func1: 0
Func1: 1
Func1: 2
Func1: 3
Func1: 4
Func1: 5
Func1: 6
Func1: 7
Func1: 8
Func1: 9
Func1 complete
Func2 complete

I am very confused about this because

IEnumerator Func1()
{
    for (int i=0; i<10; i++)
    {
        yield return null;
    }
}

IEnumerator Func2()
{
    //wait for the completion of Func1
    yield return Func1();
}

Seems to be working just fine. Did Unity do something smart to detect IEnumerators being returned?

A way that is a bit cleaner is:

IEnumerator Func2()
{
    //wait for the completion of Func1
    yield return StartCoroutine(Func1());
}

You may be over-thinking this...

`yield return Func1();`

You want this statement to "hold" until `Func1(`) is completed, right? You don't need an IEnumerator to do that... standard, regular function calls (`void Whatever();`) block the current thread until they've completed.

So if you want to call `Func1()` and have it stop the current thread until it's complete, just... call it! Your first set of code, modified, would look like this:


void Func1()
{
    for (int i = 0; i < 10; i++)
    {
        return; // return something here
    }
    return; // return something else here
}

IEnumerator Func2()
{
    //wait for the completion of Func1
    Func1();
}

And then start a new coroutine with `Func2();`.

You can also pass the IEnumerator from another function

This could allow all sorts of extensions, like a workaround for default parameters or classes or functions which cannot for whatever reason be called with a coroutine.

    [ContextMenu("Test")]
    void CallStuff()
    {
        StartCoroutine(Func2());
    }

    IEnumerator Func1(int a) 
    {
        Debug.Log("Func1 wait for " + a);
        yield return new WaitForSeconds(a);
        Debug.Log("Func1 done");
    }
    IEnumerator Func2()
    {
        Debug.Log("Func2");
        return Func1(2);
    }