Cannot null Coroutine variable if it calls an interface

Hi there!

I am creating a simple AI system for my game, and I ran into a weird issue. In my implementation the AI decides every once in a while to take an action (represented by a GameAction object), and I pass that action to a routine to be executed when certain conditions are met. I store the Coroutine object resulting from the StartCoroutine() to avoid the AI overriding an already started action:

void Update () {
	if (currentCoroutine != null) { return; }

	elapsedTime += Time.deltaTime;
	if (elapsedTime >= coroutineCallingPeriod) {
		elapsedTime -= coroutineCallingPeriod;

		currentCoroutine = StartCoroutine (GameActionCallerRoutine(new ExampleGameAction()));
	}
}

private IEnumerator GameActionCallerRoutine(GameAction gameActionToExecute) {
	// some irrelevant condition before calling Execute()
	gameActionToExecute.Execute();
	currentCoroutine = null;
	yield return null;
}

The variable currentCoroutine is set to null at the end of GameActionCallerRoutine, however, it does not work! I can notice this by no more actions being called ever again!
Upon further research it turns out that the problem is related to the routine having as a parameter an interface or abstract class (GameAction of which ExampleGameAction is a concrete implementor).

The weirdest part is that if instead of a Coroutine I store the routine before StartCoroutine() into an IEnumerator, then it can be nulled:

	// it works this way!
	currentCoroutine = GameActionCallerRoutine(null);
	StartCoroutine (currentCoroutine);

So I know I already have a solution for this, but can someone explain what’s going on here? I suspect that something stores a reference to the Coroutine object, but why can’t a variable I have complete control over set to be null just because the routine has an abstract parameter?

Thanks!
Harinezumi

You have several issues here. First of all, why are you use a coroutine at all? Your actual action method seems to be a “normal” method. So it will complete immediately within the same frame it’s called.

Your actual problems comes from the fact that when you start a coroutine Unity immediately runs the coroutine up to the next yield before the StartCoroutine call even returns. Since your first and only yield is at the end of your coroutine, you “reset” the currentCoroutine variable before it’s actually assigned.

So at the yield StartCoroutine will actually return and you assign the Coroutine object to your variable. At this point the coroutine has already done it’s “magic”. Once frame later the coroutine is done.

The way you use a coroutine here makes no sense. What does your actual “ExampleGameAction” contain? The way you’ve setup your stuff you can remove the whole coroutine stuff as it has no purpose at the moment.

If you want your GameAction to be able to execute things over several frames it should be a coroutine itself.

@Bunny83:
Thanks for the thorough response. I was also writing an answer and it is now clear what you mean: the StartCoroutine(), even before returning a Coroutine object, will run until the first yield, which means it will set currentCoroutine to null, but to no avail, because the returned Coroutine will be assigned to it. This also means that an empty yield does solve the issue.

To be honest, your somewhat offensive / contemptuous tone made me reluctant to read and analyse your answer thoroughly, but you did answer the question, and quite thoroughly. Maybe you could be a bit friendlier in the future?