Friday, April 26, 2024 12:52

Table of contents >> LINQ > Yield break statement

Yield break statement

Whenever we use the yield keyword in a statement, we indicate that the method, operator, or get accessor in which it appears is an iterator. Of course, since we know that iterators are used to… duh! iterate on collections of data, and since we know that when iterating on a collection, we can use the break keyword to immediately terminate the iteration, it is only obvious that whenever we use an yield return statement to return values in an iterator, like I’ve shown in the previous lesson, we can also use yield break to terminate the iteration of the said iterator.

This is the short version of this lesson: yield break is kinda similar to a normal break.

Now, let’s expand to the detailed explanation. In the previous lesson we initially had this code:


C# IEnumerable

A simple method inside which we were generating a bunch of random numbers, based on the _count parameter, store them in a list, and finally return that list and display its elements on the console.

Afterwards, I was explaining how we can avoid altogether the creation of a temporary list and the need to wait for the entire random numbers to be generated before returning the whole list at once, by using an yield return statement:

See code changes


Legend:

  • green lines with a plus near the line numbers are newly added lines
  • red lines with a minus near the line numbers are removed lines


C# yield return

Now, continuing on this example, let’s say we want to eliminate the _count parameter, so that the GenerateRandomNumbers() function will generate random numbers forever and ever, until we stop asking for them, like this:

See code changes


Legend:

  • green lines with a plus near the line numbers are newly added lines
  • red lines with a minus near the line numbers are removed lines


In my GenerateRandomNumbers() function, I’ve replaced the for loop with an infinite while loop, and inside the Main() method, I’m asking for these random numbers continuously until the generated number is divisible by 100, in which case I use the break operator to stop calling the GenerateRandomNumbers() function. This is the result:

This is where things start to get interesting. What if I didn’t have the yield return statement and I was forced to use a list, just like in the example at the beginning of this lesson? That would be kind of difficult:

See code changes


Legend:

  • green lines with a plus near the line numbers are newly added lines
  • red lines with a minus near the line numbers are removed lines


The code does compile just fine, but when I run my program, it’s going to crash:

You can arguably spot the problem already, even the compiler is smart enough to underline the return _temporaryList; instruction with a squiggly line, because it knows that the execution will never reach that point, since we will be forever stuck in an infinite while loop. In other words, we will continue to add elements to the _temporaryList variable until we eventually run out of RAM memory, and the program will crash.

In this case, we can try and use the break operator inside the infinite while loop, and perform the check for the number being divisible by 100 inside it, like this:

See code changes


Legend:

  • green lines with a plus near the line numbers are newly added lines
  • red lines with a minus near the line numbers are removed lines



In which case, the program will run just fine:

Now, we can return to the code version where we were not using a list at all, by replacing it with a yield return instruction, and a yield break instead of just break:
See code changes


Legend:

  • green lines with a plus near the line numbers are newly added lines
  • red lines with a minus near the line numbers are removed lines


One thing to remember is that if you are using yield break, you can no longer use the return operator, you are forced to use yield return, because you are effectively turning that method into an iterator. The compiler will give you this error: Error CS1622: Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration. So, a method cannot both use return and yield at the same time, you have to chose just one of them, because one is used by normal loops, the other is used by iterator blocks, which, as we already know, are implemented differently than normal loops.

Finally, yield break can be seen as having a single functionality, even though you might think it has two: since you can use it inside a loop, just like the normal break operator, you might think that the behavior would be the same, and it wouldn’t. Yield break is actually behaving like a return instruction, which, unlike break, which just ends the loop’s iteration and continues with the code that follows after the loop, will actually end the execution of the whole method and return it to the place where the method was called. So, yield break will not just terminate a loop, it will exit the function entirely, just like return, and it will never have a second functionality that emulates break.

Tags: , , , , , , ,

Leave a Reply



Follow the white rabbit