Peter
Peter

Reputation: 48968

Why is "while" so popular in C#?

The question field is a bit too short to pose my real question. If anyone can recapitulate it better, please feel free.

My real question is this: I'm reading a lot of other people's code in C# these days, and I have noticed that one particular form of iteration is widely spread, (see in code).
My first question is:

Are all these iterations equivalent?

And my second is: why prefer the first? Has it something to do with readibility? Now I don't believe the first form is more readable then the for-form once you get used to it, and readibility is far too much a subjective item in these constructs, of course, what you use the most will seem more readable, but I can assure everyone that the for-form is at least as readable, since it has all in one line, and you can even read the initializing in the construct.

Thus the second question: why is the 3rd form seen much less in code?

        // the 'widespread' construct
        int nr = getNumber();
        while (NotZero(nr))
        { 
            Console.Write(1/nr);
            nr = getNumber();
        }

        // the somewhat shorter form
        int nr;
        while (NotZero(nr = getNumber()))           
            Console.Write(1 / nr);            

        // the for - form
        for (int nr = getNumber(); NotZero(nr); nr = getNumber())
            Console.Write(1 / nr);

Upvotes: 4

Views: 1195

Answers (7)

Jon Skeet
Jon Skeet

Reputation: 1501626

The first and third forms you've shown repeat the call to GetNumber. I prefer the second form, although it has the disadvantage of using a side-effect within a condition of course. However I pretty much only do that with a while loop. Usually I don't end up passing the result as an argument though - the common situations I find myself in are:

string line;
while ( (line = reader.ReadLine()) != null)
...

and

int bytesRead;
while ( (bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
...

Both of these are now so idiomatic to me that they don't cause me any problems - and as I say, they allow me to only state each piece of logic once.

If you don't like the variable having too much scope, you can just introduce an extra block:

{
  int bytesRead;
  while ( (bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
  {
     // Body
  }
}

Personally I don't tend to do this - the "too-wide" scope doesn't bother me that much.

I suspect it wouldn't be too hard to write a method to encapsulate all of this. Something like:

ForEach(() => reader.ReadLine(), // Way to obtain a value
        line => line != null,    // Condition
        line =>
{
    // body
};

Mind you, for line reading I have a class which helps:

foreach (string line in new LineReader(file))
{
    // body
}

(It doesn't just work with files - it's pretty flexible.)

Upvotes: 5

tvanfosson
tvanfosson

Reputation: 532545

As for why (1) and (2) are "preferred" over (3), my feeling is that most people think of the latter as a way to iterate over a range, using the condition to define the range, rather than continuing to iterate over a block while some condition still holds. The keyword semantics lend themselves to this interpretation and I suspect that, partly because of that, people find that the expressions are most readable in that context. For instance, I would never use (1) or (2) to iterate over a range, though I could.

Between (1) and (2), I'm torn. I used to use (2) (in C) most often due to the compactness, but now (in C#) I generally write (1). I suppose that I've come to value readability over compactness and (1) seems easier to parse quickly and thus more readable to my mind even though I do end up repeating a small amount of logic.

Honestly, I rarely write while statements anymore, typically using foreach -- or LINQ -- in the cases where while statements would previously been used. Come to think of it, I'm not sure I use many for statements, either, except in unit tests where I'm generating some fixed number of a test object.

Upvotes: 1

dfa
dfa

Reputation: 116362

Are all this iterations equivalents?

yes

why prefer the first? Has it sth. to do with readibility?

because you may want to extend the scope of the nr var beyond the while loop?

why is the 3th form seen much less in code?

it is equivalent, same statements! You may prefer the latter because you don't want to extend the scope of the nr variable

Upvotes: 5

Brian
Brian

Reputation: 118875

I offer another alternative

    foreach (var x in InitInfinite(() => GetNumber()).TakeWhile(NotZero))
    {
        Console.WriteLine(1.0/x);
    }

where InitInfinite is a trivial helper function. Whole program:

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static IEnumerable<T> InitInfinite<T>(Func<T> f)
    {
        while (true)
        {
            yield return f();
        }
    }
    static int N = 5;
    static int GetNumber()
    {
        N--;
        return N;
    }
    static bool NotZero(int n) { return n != 0; }
    static void Main(string[] args)
    {
        foreach (var x in InitInfinite(() => GetNumber()).TakeWhile(NotZero))
        {
            Console.WriteLine(1.0/x);
        }
    }
}

Upvotes: 3

Svante
Svante

Reputation: 51501

I think that the third form (for-loop) is the best of these alternatives, because it puts things into the right scope. On the other hand, having to repeat the call to getNumber() is a bit awkward, too.

Generally, I think that explicit looping is widely overused. High-level languages should provide mapping, filtering, and reducing. When these high level constructs are applicable and available, looping instead is like using goto instead of looping.

If mapping, filtering, or reducing is not applicable, I would perhaps write a little macro for this kind of loop (C# doesn't have those, though, does it?).

Upvotes: 3

Brian
Brian

Reputation: 118875

Here is a random speculation:

When I write C# code, the only two looping constructs I write are while() and foreach(). That is, no one uses 'for' any more, since 'foreach' often works and is often superior. (This is an overgeneralization, but it has a core of truth.) As a result, my brain has to strain to read any 'for' loop because it's unfamiliar.

Upvotes: 2

Nippysaurus
Nippysaurus

Reputation: 20378

I think people use the while() loop often because it best represents the way you would visualize the task in your head. I think think there is any performance benefits for using it over any other loop structure.

Upvotes: 2

Related Questions