Questions about coroutines

Hi,

I have some questions about coroutines and how they’re used in the lecture “How coroutines work” and “Wait for Scene to Load”.

  1. I tried to gather some information about IEnumerators, and also found out that IEnumerators are closely related to IEnumerables. Tell me if I’m right: IEnumerables are objects which can be “counted”, and in order to be counted they need a class which count them, the Enumerator indeed (a class which implements IEnumerator’s interface). So I’m assuming that there is no IEnumerator without a IEnumerables and viceversa.
    How is this handled with coroutines? Is the object “coroutine”, in the Unity system, implementing the IEnumerable interface (I mean behind the scenes)? So is this why we need to return an IEnumerator when using a coroutine?

  2. In the example of Sam, at a certain point the GetPringles() method calls “GetEnumerator”, which is a method needed in the implementation of the IEnumerable interface. I don’t see where it is implemented, tho. Maybe in the class (that we can’t see) which implements the HungryChild method? Which, I suppose, will also derive from the IEnumerable interface?

  3. So, considering all these IEnumerators, IEnumerable and coroutines and yield return, how are all of these implemented in Unity? I’ve not found anything really “deep” in the web. Can you help me understand them better (and in a simple way, possibly :smiley: )

  4. In regards of the lecture about the loading scene, I’ve not fully understood the need to use coroutines to load the next scene. Do we want to wait for the scene to be loaded otherwise the “Portal” we are looking for would be searched in the same frame and, so, the returned portal would be in the same scene, so basically…the same portal?

  5. If we return an IEnumerator object with our implemented coroutine, how can we satisfy this condition when returning something like “yield return SceneManager.LoadSceneAsync(sceneToLoad);”? It’s a method call, so I suppose that this method, other than loading asynchronously the scene, also return some kind of IEnumerator? Or does Unity “adapt” our class behind the scenes making it automatically implementing the IEnumerator interface?
    In other words, the question is: if I yield return something, does this “something” has to be an IEnumerator? Or (maybe) the sole fact to use the keyword ‘yield return’ satisfies the need of returning an IEnumerator (since it will do some kind of code behind the scenes)?

Sorry for these questions but I basically got the argument of IEnumerable and IEnumerator interfaces with yield return statements and why someone should use them in C# (custom iteration and stateful iteration), but it’s not entirely clear to me how do they work in Unity’s coroutines.

Thanks in advance and best

Jader

That’s a good healthy stack of questions… I’ll try to tackle these as best I can, though some of the answers will be “magic” (or more like - Unity manages this behind the scenes in a proprietary way).

  1. See “magic”. Unity is actually taking advantage of the nature of an IEnumerator to “fake” a new thread. Bear in mind that what’s not happening behind the scenes is an actual new thread. At the end of the Update() phase, Unity goes through all of the active IEnumerators and gives them a turn if the conditions have been met. If the condition has been met, the IEnumerator gets it’s turn.

  2. See “magic”. The call to GetEnumerator() happens completely behind the scenes in most cases. Take a foreach loop, for example (foreach runs over an IEnumerable collection).

foreach (Pringle chip in chips)
{
    //GetEnumerator called behind the scenes
    chip.AddDip();
    chip.Consume();
}
  1. See “magic”. Unfortunately, no. The important thing is that they work.

  2. That’s exactly correct. By using the Coroutine, we can wait until the loading of the next scene has progressed before we move the character to the next portal (and later when we introduce saving and loading, so we can restore the status of the characters in the scene from a save file!) We can’t act until the scene is loaded or we’ll be working on nothing at all.

  3. LoadSceneAsync actually returns something that is functionally equivilant to an IEnumerator object. Much like yield return new WaitForSeconds(x);, control resumes when the Async operation has completed. To the second part of this, yield return; won’t work, but yield return null; will (and is functionally equivilant to yield return new WaitTillEndOfFrame(); Control is passed back to the game loop and the coroutine will resume in the next frame.

Thanks Brian, that brought some light on the topic to me :slight_smile:
The only real point that is still unclear is the first question. Where is the IEnumerable interface implemented, when using coroutines?

Thanks again for the answers!
Best,

Jader

P.s.: I think I’m able to use coroutines quite decently now but just wanted to understand more their deep functioning!

Somewhere in the StartCoroutine method. Just for fun, I’ll dig into the source code…
In MonoBehavior.cs:

    /// <summary>
    ///   <para>Starts a Coroutine.</para>
    /// </summary>
    /// <param name="routine"></param>
    public Coroutine StartCoroutine(IEnumerator routine)
    {
      if (routine == null)
        throw new NullReferenceException("routine is null");
      if (!MonoBehaviour.IsObjectMonoBehaviour((Object) this))
        throw new ArgumentException("Coroutines can only be stopped on a MonoBehaviour");
      return this.StartCoroutineManaged2(routine);
    }

So StartCoroutine does some sanity checks, makes sure the routine is not null and that it’s being called from a MonoBehavior, then calls StartCoroutineManaged2(routine);

    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern Coroutine StartCoroutineManaged2(IEnumerator enumerator);

What this means is that it calls a routine Unity wrote in C++ and compiled, keeping the source code of what’s really going on out of our hands… see "Magic"

This topic was automatically closed after 22 hours. New replies are no longer allowed.