Using C# Yield for Readability and Performance

I must have read about "yield" a dozen times. Only recently have I began to understand what it does, and the real power that comes along with it. I’m going to show you some examples of where it can make your code more readable, and potentially more efficient.

To give you a very quick overview of how the yield functionality works, I first want to show you an example without it. The following code is simple, yet it’s a common pattern in the latest project I’m working on.

IList<string> FindBobs(IEnumerable<string> names)
{
	var bobs = new List<string>();

	foreach(var currName in names)
	{
		if(currName == "Bob")
			bobs.Add(currName);
	}
	
	return bobs;
}

Notice that I take in an IEnumerable<string>, and return an IList<string>. My general rule of thumb has been to be as lenient as possible with my input, and as strict as possible with my output. For the input, it clearly makes sense to use IEnumerable if you’re just going to be looping through it with a foreach. For the output, I try to use an interface so that the implementation can be changed. However, I chose to return the list because the caller may be able to take advantage of the fact that I already went through the work of making it a list.

The problem is, my design isn’t chainable, and it’s creating lists all over the place. In reality, this probably doesn’t add up to much, but it’s there nonetheless.

Now, let’s take a look at the "yield" way of doing it, and then I’ll explain how and why it works:

IEnumerable<string> FindBobs(IEnumerable<string> names)
{
	foreach(var currName in names)
	{
		if(currName == "Bob")
			yield return currName;
	}
}

In this version, we have changed the return type to IEnumerable<string>, and we’re using "yield return". Notice that I’m no longer creating a list. What’s happening is a little confusing, but I promise it’s actually incredibly simple once you understand it.

When you use the "yield return" keyphrase, .NET is wiring up a whole bunch of plumbing code for you, but for now you can pretend it’s magic. When you start to loop in the calling code (not listed here), this function actually gets called over and over again, but each time it resumes execution where it left off.

Typical Implementation

Yield Implementation
  1. Caller calls function
  2. Function executes and returns list
  3. Caller uses list
  1. Caller calls function
  2. Caller requests item
  3. Next item returned
  4. Goto step #2

Although the execution of the yield implementation is a little more complicated, what we end up with is an implementation that "pulls" items one at a time instead of having to build an entire list before returning to the client.

In regards to the syntax, I personally think the yield syntax is simpler, and does a better job conveying what the method is actually doing. Even the fact that I’m returning IEnumerable tells the caller that its only concern should be that it can "foreach" over the return data. The caller can now make their own decision if they want to put it in a list, possibly at the expense of performance.

In the simple example I provided, you might not see much of an advantage. However, you’ll avoid unnecessary work when the caller can "short-circuit" or cancel looping through all of the items that the function will provide. When you start chaining methods using this technique together, this becomes more likely, and the amount of work saved can possibly multiply.

Ayende has a great example of using yield for a slick pipes & filters implementation. He even has a version that is multi-threaded which I find very intriguing.

One of my first reservations with using yield was that there is a potential performance implication. Since c# is keeping track of what is going on in what is essentially a state machine, there is a bit of overhead. Unfortunately, I can’t find any information that demonstrates the performance impact. I do think that the potential advantages I mentioned should outweigh the overhead concerns.

Conclusion

Yield can make your code more efficient and more readable. It’s been around since .NET 2.0, so there’s not much reason to avoid understanding and using it.

You can find detailed information about how the yield keyword works under the hood here.

Have you been using yield in interesting ways? Have you ever been bitten by using it? Leave a comment and let me know!

37 comments on “Using C# Yield for Readability and Performance
  1. Have you included the “yield return break” for any reason? As far as I know it is superfluous in this case.

  2. admin says:

    Great catch Garry!

    I updated the post and removed it. That statement was wrong either way, it should have been “yield break”.

  3. I think the performance implications are going to vary depending on what you are doing. If you are dealing with very large lists then you could very well improve performance because you don’t have to deal with a bunch of items being in memory at the same time.

    Another important consideration is in lists where you don’t enumerate the entire thing. In which case using yield could be faster since you aren’t going to waste time spinning through the entire list.

    And lastly, you also have to consider infinite series, which would not be possible at all using your original code. Perhaps I’ll write up a blog post discussing this topic. Hmmmmm. :-)

  4. Licantrop0 says:

    A Linq2Entities solution could be clearer?

    return names.Where(n => n == “Bob”);

    you get rid also of the foreach cycle.

  5. admin says:

    @Justin
    Yes, those reasons were part of the point I was trying to make. As far as the infinite series, people have mentioned that before, but it’s honestly not something I’ve actually seen a common need for. I wrote this post because I was only seeing the examples showing me how to get x digits of PI which isn’t terribly useful.

    @Licantrop0
    Yes, you could do that as well. In my actual code, I’m doing a little more advanced filtering. I simplified it to make the example easy to digest.

  6. Tom says:

    Great information! Thanks!

    One caveat is that you cannot use YieldingFunction().Count. that would clearly defeat the point of the yield, anyway.

  7. Petar Repac says:

    yield return statement essentially makes the method a coroutine (http://en.wikipedia.org/wiki/Coroutine). It makes deferred query execution possible and is a basis for LINQ.

  8. Judah Himango says:

    Yield return allocates a new class in the background, so it can be more expensive in terms of memory usage.

    Like Justin said, it depends on how you’re using it.

  9. I found something interesting about yield too when working with Entity Framework.
    For example if you have and Entity with called Category and You wished to make it implement interface called ICategory.
    Using ObjectContext.CreateQuery.Cast() would through an exception.
    I made a workaround this issue by using yield.

    I made something the below wrapped in a method
    foreach(var cateogry in context.CategorySet)
    yield return category as ICategory

    This is not going to be evaluated immediatly,
    for example if you put this in a method called GetEnumerable() and called this method like this
    var x = context.GetEnumerable();
    this will not hit the database and evaulate your query.
    What will hit the database is when you start iterating.
    Thought to share it here on this cool post

  10. sgwong says:

    It looks like ruby yield statement. In ruby, yields is everywhere and straight forward, easy to use.

  11. trendbender says:

    very interesting, thx)

  12. Timeless says:

    Excellent post, thanks. Like yourself, I read several times about the yield topic but never really graspt the idea and therefore never used it so far. I can surely see areas where yield can be quite useful, thanks again for the clear example and explanation.

  13. micaleel says:

    really nice. Thanks

  14. Tuan Jinn says:

    Awesome,
    Interesting information and I have been usin’ yield for awhile now.
    Thanks,

    Tuan Jinn

  15. Tuan Jinn says:

    I encountered some problems (logical) while refactoring my code, which I am in doubt of using Yield.
    I googled up and found this:
    http://www.c-sharpcorner.com/UploadFile/dhiren.i.patel/Yield02092009234408PM/Yield.aspx

    pretty disappointed about that post and clue less about whose is the original post.

    Words are almost the same, except the method names are different.

    Can you report or explain that? I’m quite allergic to this.

    Tuan Jinn

  16. admin says:

    Tuan, I have contacted that site to have that removed. This post was copied without my permission.

    Thank you for reporting that.

  17. t4 says:

    I found the same article as Tuan (along with your own article, which looks to be the true source), and the article mentioned by Tuan still seems to be active. The author (patel.dhiren.i@gmail.com) doesn’t seem to have any reservations about copying your article for his own uses…

  18. This was helpful, thanks!

  19. Matthew says:

    I haven’t checked memory usage, but yield appears to be awesome speed-wise, at least in this simple little test I ran.

    Say I want to return a list of 20 items to process. The fastest way to allocate such a list should be a single allocation of a fixed size array, but it turns out that allocation, copying, and processing takes about 20% longer than creating an IEnumerable to directly iterate through the items. The advantage of the second case of course is there’s no need to copy the elements. You just allocate and access.

    // elapsed: 00:00:03.4531250
    static IEnumerable GetNumbers()
    {
    for(int i = 0; i < 20; i++)
    {
    yield return i;
    }
    }

    // elapsed: 00:00:04.2500000
    static IEnumerable GetNumbersArray()
    {
    int[] retval = new int[20];

    for(int i = 0; i < 20; i++)
    {
    retval[i] = i;
    }

    return retval;
    }

    static void Main(string[] args)
    {
    int sum = 0;
    DateTime begin = DateTime.Now;
    for(int i = 0; i < (1 << 24); i++)
    {
    foreach(int j in
    /*
    GetNumbers()
    */
    GetNumbersArray()
    )
    {
    sum += j;
    }
    }
    DateTime end = DateTime.Now;
    Console.WriteLine(
    “elapsed: ” +
    (end – begin).ToString()
    );
    Console.WriteLine(sum);
    }

  20. Matthew says:

    I hate these web-based interfaces. That was supposed to be the typed version, IEnumerable&ltT>, not IEnumerable which is much slower.

  21. Ed says:

    Why not just have a count property and a getItem(int index) method. Perfect clarity, less overhead and no surprises (also totality thread safe).

  22. Nariman says:

    There are definite performance gains to be had – here’s a good sample:
    http://flimflan.com/blog/ThePowerOfYieldReturn.aspx

  23. User says:

    public IEnumerable Comment()
    {
    yield return “Good post!!”;
    }

  24. Niels R. says:

    At the above user: Too bad, but this will not work. “yield” must be used inside an iteration… ;o)

    I like the idea of your comment, though!

  25. Runcust says:

    Good job explaining this topic. Great!!! I have been looking at so many other examples etc. and was still a little confused. THANKS!!!!

  26. Chuck Norris says:

    omfg, I misread “FindBobs” and thought of something inappropriate for a moment =)
    other than that excellent example!

  27. Sunil Chitrapu says:

    Very useful information

    Thanks for the post

  28. Pete says:

    Thanks for this I too read about yield a few times in the past and didn’t understand it although that was before I was using lots of Generics and Linq. This example makes it easy to understand.

  29. jayasuthan says:

    The purpose of the yield is only to inform to the compiler that the foreach loop in the function called from inside the foreach loop is not finished.

    Other wise it will execute the whole coding in that function

  30. shefeek says:

    Good post dude..
    I dont know why you put the conclusion on performance in agnostic way.
    Just like justin said there are areas that we need to use to improve the performance.
    Thanks,
    shef

  31. Andy says:

    Thanks! I wish I found this post 2.5 years ago when you wrote it, but I am glad I found it now. You explained this quite simply!

  32. Matt says:

    Still don’t understand what yield is supposed to do. Sounds terribly inefficient, why would I want to pull records 1 at a time? I can’t more forward until I have all the results anyway.

  33. zul says:

    Thank you, easy to understand, thanks a lot..

  34. aifsxldcz says:

    Hello here
    http://www.ytechie.com is a good forum
    I spent 8 hours searching in the network, until find your forum! I think, I shall stay here for a long time!

  35. My brother recommended I might like this blog.
    He was totally right. This post truly made my day. You cann’t imagine simply how much time I had spent for this info! Thanks!

16 Pings/Trackbacks for "Using C# Yield for Readability and Performance"
  1. [...] Jason Young tells us about Using C# Yield for Readability and Performance. [...]

  2. [...] Using C# Yield for Readability and Performance [...]

  3. [...] Using C# Yield for Readability and Performance [...]

  4. [...] For a moment, forget that LINQ exists. Let’s say that you wanted to filter a list of names, to only get names that start with the letter “J”. You could write the following “utility” function: (if you don’t understand “yield return”, see this post on that topic). [...]

  5. [...] Until now the dominating pattern regarding sequential input was the IEnumarable interface and the “yield” keyword in C#. Since the advent of LINQ and the deferred execution mechanism, this Design Pattern has received a [...]

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>