tags:

views:

458

answers:

7

Syntactically I see that they loop indefinitely until a break statement is reached, but are they compiled to the same thing? Is the for slightly faster because it doesn't have a condition to check? Aside from code readability, is there even a difference?

+2  A: 

I haven't examined the output code, but there should be no difference whatsoever. Any decent compiler will do simple enough loop optimization to see that the condition is a constant expression, and thus doesn't need checking every iteration.

If one is faster than the other, the C# compiler writers need something 'splained to them...

T.E.D.
+16  A: 

In modern compilers, absolutely nothing.

Historically, however, for(;;) was implemented as a single jump, while while(true) also had a check for true.

I prefer while(true), since it makes it more clear what I am doing.

Mike Caron
+1 absolutely. `while(true)` is much more clear than `for(;;)`. What am I waiting for, anyway?
Matthew Jones
I heartily agree that you should pick the one you think is clearer, although I might disagree on which one that is...
T.E.D.
why not `loop: ... goto loop` ?
Bertrand Marron
OMG! NOT `goto`! IF WE USE THAT, THE WORLD WILL END!
Mike Caron
The world might or might not end, but using `goto` can disable all optimizations.
Steven Sudit
You sure about that? How do you think the compiler implements flow control?
Mike Caron
I don't think the world would end if we used `goto`, but it might abruptly jump to a new location in the universe.
Dr. Wily's Apprentice
@Mike: The compiler does use branches and jumps, but in order for it to optimize your code, you have to avoid `goto`.
Steven Sudit
@Steven: I highly doubt that. There are reasons to avoid `goto`, but optimization is not one of them. The C# compiler doesn't do any heavy optimization, relying on the CLR to optimize the JIT'd code. In this situation, a user-specified `goto` and a copiler specified `goto` are exactly the same. (And, you can look that up)
Mike Caron
@Mike: You might be right about C#, but I know this was the case with MSVC++ and a number of other C++ compilers.
Steven Sudit
@Steven: That very well may be, my expertise is in C# :)
Mike Caron
+27  A: 

Given this input:

private static void ForLoop()
{
    int n = 0;
    for (; ; )
    {
        Console.WriteLine(n++);
    }
}

private static void WhileLoop()
{
    int n = 0;
    while (true)
    {
        Console.WriteLine(n++);
    }
}

...you get this output:

.method private hidebysig static void  ForLoop() cil managed
{
  // Code size       14 (0xe)
  .maxstack  3
  .locals init ([0] int32 n)
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  dup
  IL_0004:  ldc.i4.1
  IL_0005:  add
  IL_0006:  stloc.0
  IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000c:  br.s       IL_0002
} // end of method Program::ForLoop


.method private hidebysig static void  WhileLoop() cil managed
{
  // Code size       14 (0xe)
  .maxstack  3
  .locals init ([0] int32 n)
  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  dup
  IL_0004:  ldc.i4.1
  IL_0005:  add
  IL_0006:  stloc.0
  IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000c:  br.s       IL_0002
} // end of method Program::WhileLoop

Remarkably similar, I would say (identical, even).

Fredrik Mörk
Unless I'm missing something, they are *identical*, outside of the comments and identifier names.
T.E.D.
@T.E.D. yes, they are identical.
Fredrik Mörk
Hmm, there's a difference on line 5... oh, wait, no that's a spot on my monitor ;)
Mike Caron
Are we *really* debating the relative speed of infinite loops?
Steven Sudit
@Steven: I certainly hope not. We are satisfying our curiosity. At least I am.
Fredrik Mörk
There are not a lot of examples of the C# compiler optimizing the code. Normally the JIT compiler does the job. This is one of them though.
Hans Passant
@Steven, one infinite loop could terminate earlier than the other, if it makes more excessive contributions to the eventual heat decay of the universe than the other loop.
Nathan Ernst
@Nathan you can't really rely on that behaviour, though. Currently, it's theorized that the loop will terminate, but it's also possible that in the future the universe will throw a `CausalityViolatedException` instead.
Mike Caron
@Fredrik: I would hope not, as well, but look at Nathan's response. :-)
Steven Sudit
A: 

They compile to the same thing. You can write a test app that implements both methods and then use ILDASM to confirm they IL is identical.

Darvis Lombardo
Or you can just look at Fredrik's answer and save yourself the trouble. :)
Darvis Lombardo
A: 

A debug assembly complies down to while(true). Use reflector and you can see the results.

    static void Main(string[] args)
    {
        ExecuteWhile();

        ExecuteFor();
    }

    private static void ExecuteFor()
    {
        for (; ; )
        {
            Console.WriteLine("for");
            string val = Console.ReadLine();
            if (string.IsNullOrEmpty(val))
            {
                Console.WriteLine("Exit for.");
                break;
            }
        }
    }

    private static void ExecuteWhile()
    {
        while (true)
        {
            Console.WriteLine("while");
            string val = Console.ReadLine();
            if (string.IsNullOrEmpty(val))
            {
                Console.WriteLine("Exit while.");
                break;
            }
        }
    }

Inspecting the ExecuteFor method in Reflector.

private static void ExecuteFor()
{
    while (true)
    {
        Console.WriteLine("for");
        if (string.IsNullOrEmpty(Console.ReadLine()))
        {
            Console.WriteLine("Exit for.");
            return;
        }
    }
}

An optimized version of the same code produces different results for ExecuteFor

private static void ExecuteFor()
{
    do
    {
        Console.WriteLine("for");
    }
    while (!string.IsNullOrEmpty(Console.ReadLine()));
    Console.WriteLine("Exit for.");
}

For verbosity here is the optimized ExecuteWhile...

private static void ExecuteWhile()
{
    do
    {
        Console.WriteLine("while");
    }
    while (!string.IsNullOrEmpty(Console.ReadLine()));
    Console.WriteLine("Exit while.");
}
Wil P
Does it really compile down to `while(true)`, or does Reflector decompile it that way? :p
Mark H
If you look at the IL created from the same assemblies it reads that way.
Wil P
A: 

As mentioned by others, with any modern compiler, it should make absolutely no difference.

I did a brief test on my computer, timing a couple of operations using one or the other, and they always took pretty much the same time. Of course, because of other processes running, these tests aren't 100% accurate, but if there is a difference in speed (there shouldn't be) then it is a microscopic one.

EdoDodo
+1  A: 

If I might, I'd suggest that you look at a somewhat different question. If you're using either of these often enough to care, you're probably structuring your code poorly. While there are things like embedded systems that really do run forever, loops in most normal code do not. Writing a loop that claims to run forever usually means you've hidden the exit condition for the loop somewhere inside, with some other control flow (e.g., if (whatever) break;) as the real exit from the loop.

That can and usually should be avoided. While there are situations where break statements make sense, they should generally be to handle unusual situations, not for writing a loop that says one thing but does another (i.e., says "run forever", but really does "run until condition is met").

Jerry Coffin
I can't agree with this.
Steven Sudit
Me neither. When I was first learning to program in PL/I (I don't know if it even had a 'break' statement) the pattern was "read line of file; while it's not the end-marker, do the loop, which ends with reading the next line". That seems a violation of "don't repeat yourself". I would suggest that reading the line once, at the start of the loop, and exiting if it's an end-marker, is a better style.
supercat
@supercat: I agree, but it doesn't justify anything. You should be doing `while (file.getline())`, not `for (;;) if (!file.getline()) break;`
Jerry Coffin
@supercat: Yes, it's often cleanest to put the test into the *middle* of the loop and break out of it when it fails.
Steven Sudit
@Jerry: That's a plausible example, but hardly the only way things work. The sentinel could instead be a specific value, such as a "0".
Steven Sudit
@Steven: The value of the sentinel rarely (if ever) matters. Something like `for (;;) { x = next_value(); if (x == sentinel) break; process(x); }` can essentially always be converted to something like `while ((x=next_value()) != sentinel ) process(x);`.
Jerry Coffin
I once wrote an RFC 822 header parser that looped until it hit an empty line, but inside that loop it also had to peek ahead to see if the next line is a continuation and keep looping internally until it concatenated the whole thing. After all that, it had to check that the key/value pair was both syntactically and semantically valid, exiting if not. I suppose it's possible to obfuscate this so as to avoid a `while(true)` but why bother? This is a genuine case of multiple exit criteria that cannot be determined in a single location on top.
Steven Sudit
My conclusion from this is that avoidance of the infinite loop with internal breaks is a pointless ideal that only *hurts* code quality.
Steven Sudit
@Steven: I was very careful to say it should "usually" be avoided. Yes, insisting on avoiding it even when it's the only reasonable solution can reduce code quality -- but that's really pretty rare. The *usual* result is an improvement in code quality.
Jerry Coffin
I'm skeptical even about "usually". In your example, you show assignment and comparison being combined, but that's a bad practice.
Steven Sudit
@Jerry Coffin: That while() loop condition exceeds my threshold for how many side-effects an expression can have before it's considered ridiculous. Why bother with a loop body at all? Why not "while ((((x=next_value()) != sentinel) "?
supercat
@Supercat: Because just as the condition for exiting the loop *should* be in the loop condition, other code like `process(x);` that does *not* form part of the condition for exiting the loop should *not* be in the loop condition. "Think before you ask these things!"
Jerry Coffin
@Jerry Coffin: I was being a little sarcastic; my point was that I dislike writing conditional expressions with excessive side-effects, and I think your example is really pushing things. I don't mind "if" statements that directly check whether a function works, nor do I mind "do {} while(--i);" but side-effect-laden expressions at the top of a loop don't feel right to me.
supercat