Wednesday, May 14, 2008

Yield The Danger

In "Return Yield and Return"
http://andrewboland.blogspot.com/2008/05/return-yield-and-return.html
I pointed out the odd implementation and behavior of the yield statement.

Here is an example of unexpected behavior of yield. Consider the code:

class Program
{
public static int globalCount;
static void Main(string[] args)
{
foreach (int number in collection())
{
Console.WriteLine(number.ToString());
SecretFunction();
}
Console.ReadLine();
}
private static IEnumerable collection()
{
globalCount = 1;
yield return globalCount;
globalCount++;
yield return globalCount;
globalCount++;
yield return globalCount;
}
private static void SecretFunction()
{
//
}
}

/////////////////
As written this results in the output:
1
2
3

However if the body of SecretFunction() is replaced with
globalCount = 0;

The resulting output is:
1
1
1

According to the rules this is all correct but this might come as a surprise.
We are used to considering functions in isolation. In fact this is the prime reason for functions. By isolating code we reduce the cognitive load required. But given the way yield is implemented this cognitive load is radically increased. We cannot mentally checkoff the collection function, we have to be aware of this behavior.

It gets worse if we touch this code. Consider if we change the collection function with this allegedly equivalent code:

private static IEnumerable collection()
{
List list = new List();
list.Add(1);
list.Add(2);
list.Add(3);
return list;
}

/////////
Under both implementations of SecretFunction, it results in:
1
2
3

/////////
What are we to think here?
There is no doubt this will result in unexpected bugs being coded as result of this obscure behavior of yield.

permalink

No comments: