tags:

views:

1128

answers:

6

Can anyone see a use for the "yield break" statement that could not have been otherwise achieved by using "break" or "return".

This statement seems to be utterly useless. What's more, without this statement, the "yield return X" statement could have been simplified to "yield X", which much more readable.

What am I missing?

+3  A: 

yield break specifies that the method should stop returning results. "return" by itself would not be good enough, or could even lead to a bug, because the return type of the method has to be IEnumerable.

I am not sure why the return keyword is also needed. My best guess would be that it helps make the intention of the statement a little clearer.

If you are interested, this article explains what yield is doing behind the scenes

Behind the scenes of the C# yield keyword

Bob
That's not the way I read the behavior- 'yield break' cancels the entire method, returning nothing. You could have 'yield return(ed)' 10K items, but if a 'yield break' is then hit within the same method you get 0 items total.
Dave Swersky
@Dave: I don't think so... how is lazy-evaluation going to work in an iterator block then?
chakrit
@Dave, nope, yield break stops any more items from returning, but does not (and cannot) cancel that have already been returned.
configurator
@Bob: "return" by itself wouldn't lead to a bug - it simply won't compile inside an iterator block. The 'yield return' keyword combination is necessary to prevent breaking existing code.
configurator
@configurator, Miles asked why you can't use return by itself, if this was allowed, the syntax could be confusing which could lead to bugs.
Bob
@Dave, think about the break keyword inside of a for or foreach. Just because you break doesn't mean the code executed before it gets undone. When you yield a return value the execution of the method is essentially paused and will resume when the next item is requested.
Bob
A: 

You need to have a distinction between returning an IEnumerable implementation that already exists (perhaps you are going to return a List) and an anonymous iterator.

You can't just use return or break because those are valid keywords that can be used for other purposes. You also can't use yield on it's own because you need to have a way to specify if you are returning an item in the enumeration, or ending the enumeration, hence the need for yield return and yield break.

casperOne
+2  A: 

It is illegal to use a return statement in an iterator block. Moreover, the break statement could serve a dual purpose within an iterator block if it were to be allowed to affect the iteration: it could be used to break out of a loop or out of a switch, and it could be used to break out of the whole iteration.

yield return and yield break and are two keywords in and of themselves, and they both seem to be necessary.

Justice
A: 

return statement is used to return a value from a function.

If you have an iterator function like this:

public IEnumerable<int> IteratorOverInt() { }

a return statement in the above function would need to return a filled IEnumerable<int>.

public IEnumerable<int> IteratorOverInt() {
    return new List<int> { 1, 2, 3, 4 };
}

but if you are working on an iterator function, you will be using yield return, so your code might look like this:

public IEnumerable<int> IteratorOverInt() {
    for (int i = 0; i < 4; i++) {
        yield return i;
    }
}

So yield return is returning an int while the method signature demands IEnumerable<int>

What would a return statement do in the above case? Return results overriding the yields? Concatenating whatever to the yields? return doesn't make much sense in the above case.

Thus we need a way to return that make sense in an iterator block, which is why there is yield break.

Of course you can do it with a break, but then how would you exit the function body if you have more code that'd execute? Wrap everything in a complicated if-else block? I'd say just having yield break would be better.

chakrit
+3  A: 

To give a code example, say you want to write an iterator that returns nothing if the source is null or empty.

public IEnumerable<T> EnumerateThroughNull<T>(IEnumerable<T> source)
{
    if (source == null)
        yield break;

    foreach (T item in source)
        yield return item;
}

Without the yield break it becomes impossible to return an empty set inside an iterator.

Cameron MacFarland
@Cameron: thanks for this code sample, it helped me with a problem I was having! Kudos!
p.campbell
yield break returns an empty enumerable... essentially (in your case) the same as `return new T[0]` but without creating an empty array.
Will
Well we could just make the if statement only run if source!=null, but point taken
Casebash
+2  A: 

yield break and break do completely different things! Look

for(int i = 0; i < 10; ++i) {
   if(i > 5) { break; }
   yield return i;
}

for(int v = 2710; v < 2714; v+=2) {
   yield return v;
}

for(int s = 16; s < 147; ++s) {
   if(s == 27) { yield break; }
   else if(s > 17) { yield return s; }
}

Output would be an IEnumerable of these values: 0, 1, 2, 3, 4, 5, 2710, 2712, 18, 19, 20, 21, 22, 23, 24, 25, 26

Here's some method which does nothing useful, but it illustrates that you can combine yield break and break into the same method, and they do two different things! Break just breaks out of the loop, yield break ends the method completely.

I guess the reason return isn't used is because you're not returning an IEnumerable yourself in the method. Besides, don't you think yield break is clearer than return, for this kind of iterative situation? I do personally.

Ray Hidayat
lol oh whoops I didn't mean for it to do that, I'll fix that.
Ray Hidayat