So I thought I understood c# yield return as being largely the same as pythons yield which I thought that I understood. I thought that the compiler transforms a function into an object with a pointer to where execution should be resumed and when a request for the next value comes along the object runs up to the next yield where it updates the pointer of where to resume execution and returns a value.
In python this works sort of similarly to lazy evaluation in that it produces values as needed but once the values are used once they can be gc'ed if not save in another variable. Trying to iterate over the result of such a function twice returns an empty iterable unless you transform it to a list.
ex.
def y():
list = [1,2,3,4]
for i in list:
yield str(i)
ys = y()
print "first ys:"
print ",".join(ys)
print "second ys:"
print ",".join(ys)
outputs
first ys:
1,2,3,4
second ys:
Until recently I thought the same thing was true for c# but trying it out in dotnetfiddle failed.
http://dotnetfiddle.net/W5Cbv6
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static IEnumerable<string> Y()
{
var list = new List<string> {"1","2","3","4","5"};
foreach(var i in list)
{
yield return i;
}
}
public static void Main()
{
var ys = Y();
Console.WriteLine("first ys");
Console.WriteLine(string.Join(",", ys));
Console.WriteLine("second ys");
Console.WriteLine(string.Join(",", ys));
}
}
outputs
first ys
1,2,3,4,5
second ys
1,2,3,4,5
What is happening here? Is it caching the result? It can't be right, otherwise File.ReadLines would blow up on huge files? Is it simply restarting the function from the top a second time?
note: I'm a bit uncertain about some of the terminology of generators and coroutines so I've tried to avoid labelling.
You're very close. An IEnumerable
is an object capable of creating an iterator (an IEnumerator
). An IEnumerator
behaves exactly as you've described.
So the IEnumerable
generates generators.
Unless you go out of your way to generate some sort of state shared between the generated iterators, IEnumerator
objects won't affect each other, whether they are from separate calls to the iterator block or another IEnumerator
generated by the same IEnumerable
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With