Inspired by Scott Hanselman's quest to read source code to be a better developer I decided to start a series of blog posts and write about anything which comes to my mind in the everyday encountering with THE code here at Telerik. As Scott is doing a great job with his quest I would rather focus on topics in which the distinction between right and wrong is not clear enough. I'm not talking about starting flame wars but rather talking about all the aspects and the different pros and cons of each approach.

Today's topic will be about infinite loops and mostly about infinite loops in which you additionally need some counter in order to use it as an indexer for a collection or for some logging purposes. Typically you need such loops when the break condition is not easily definable. In most cases first you don't even need a counter and the most natural thing to write is:

while (true)  
{  
    ...  
    if (some_condition)  
        break;  

 

Later on you may extend this code with:

int i = 0;  
while (true)  
{  
    ...  
    if (some_condition)  
        break;  
 
    i++;  

 

Of course there's nothing wrong with this unless you (like me) dislike using the "while (true)" statement. May be I dislike it because of this - it acts like a statement but still it's not a "legal" statement. Anyway, this is just my prejudice and you don't need to take it into consideration.
The other way to do the same is writing:

for (int i = 0; i < int.MaxValue; i++)  
{  
    ...  
    if (some_condition)  
        break;  

 

This looks pretty neat and now we don't have "so infinite" loop which could possibly cause an OutOfMemoryException.
Inspired by Matthew Podwysocki's "quest to deliver F# goodies to C#" you could use the Unfold method to define an infinite collection. I've attached a sample project where you could find the necessary classes. With the InitializeInfinite method you could do the following:

var infiniteSequence = UnfoldHelper.InitializeInfinite(x => x + 1);  
foreach (var i in infiniteSequence)  
{  
    ...  
    if (some_condition)  
        break;  
}  
 

 

The benefit of using the Unfold method is that you could easily define different both finite and infinite collections without the need to create new classes and yielding custom sequences.
For example with Unfold you could get and the Fibonacci sequence the following way:

 
Unfold(x => Option.Some(Tuple.New(x.Item1, Tuple.New(x.Item2, x.Item1 + x.Item2))), Tuple.New(1, 1));   
 

 

Not that you'll need the Fibonacci sequence (maybe for calculating the story points of a large user story :) that often but just in case.
Maybe you'll feel tempted to do the following and save an extra line of code:

UnfoldHelper.InitializeInfinite(x => x + 1).ForEach(i =>  
{  
    ...  
    if (some_condition)  
        return;  
}); 

 

First maybe you've noticed that I've used a custom "ForEach" extension method rather than calling ToList().ForEach. Calling the ToList() method for an infinite sequence is a BAD idea. Second the truth is that even with a custom ForEach method the "return" won't get you out of the Action as the ForEach extension method won't respect it. We could achieve a good result with a Func returning a boolean but this way the lines of code will grow which is not the desired effect :)

Should you think of other approaches or pros and cons which I’ve not mentioned, feel free to comment.

Source Code


About the Author

Hristo Kosev

 

Comments

Comments are disabled in preview mode.