23

This is a long running debate between me and my teacher. Can there be a situation where a for loop absolutely cannot be used in place of a while/do-while loop? In other words, is there a specific case where a for-loop will not work in place of a while loop; is while/do-while in any way "distinct" from for?

arshajii
  • 127,459
  • 24
  • 238
  • 287
REGAL
  • 326
  • 2
  • 9

4 Answers4

37

No, there is no such situation. Every do-while loop can be written in terms of a while-loop (by executing the body once before the loop) and vice versa. In turn, every while-loop

while (X) {
    ...
}

can be written as

for (; X;) {
    ...
}

i.e. we omit an initialization and an increment statement. We can also convert from a for back to a while by correctly placing the initialization and increment.

In short, it's always possible to convert from one loop variant to either of the other two. for-loops just give you the benefit of being able to limit the scope of a loop control variable and do any incrementation at the top. It goes without saying that in many cases one particular loop variant makes much more sense to use than the others; each has its specific use cases.

Also note that the fun doesn't just end with loops: it's also possible to convert every loop into a recursive function and vice versa (although in practice there could be limitations to this; for example a loop that worked fine could, when converted to a recursive function, produce a stack overflow error).


[I]s while/do-while in any way "distinct" from for?

It is not. For instance, the bytecode of the following two snippets is identical:

int x = 0;
while (x < 10) {
    x++;
}

and

int x = 0;
for (; x < 10;) {  // or: for (; x < 10; x++) {}
    x++;
}

both become:

   0: iconst_0      
   1: istore_1      
   2: goto          8
   5: iinc          1, 1
   8: iload_1       
   9: bipush        10
  11: if_icmplt     5
  14: return 

There was talk in the comments about for-each loops and that they might be intrinsically different from the other loop types. This is absolutely not true; for-each loops are pure syntactic sugar around iterators (or looping over arrays). Every for-each loop can also be converted to each of the other loop types. Here's an example:

for (String s : l) {  // l is a list of strings
    System.out.println(s);
}

and

String s;
Iterator<String> iter = l.iterator();  // l is a list of strings
while (iter.hasNext()) {
    s = iter.next();
    System.out.println(s);
}

both become:

  24: invokeinterface #33,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
  29: astore_3      
  30: goto          50
  33: aload_3       
  34: invokeinterface #39,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
  39: checkcast     #19                 // class java/lang/String
  42: astore_2      
  43: getstatic     #45                 // Field java/lang/System.out:Ljava/io/PrintStream;
  46: aload_2       
  47: invokevirtual #51                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
  50: aload_3       
  51: invokeinterface #57,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
  56: ifne          33
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • 6
    And `for` and `while` loops are just syntactic sugar around conditional jumps! – chrylis -cautiouslyoptimistic- Oct 09 '13 at 17:25
  • 1
    @chrylis And conditional statements are just syntactic sugar for branching! – Cruncher Oct 09 '13 at 17:28
  • 2
    @Cruncher No, branching is the fundamental operation in every real-world architecture I'm familiar with; it (optionally) makes a comparison and then overwrites the program counter with a new target. In the JVM, it's [`if`](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.if_cond), and in x86, it's the `J*` opcodes. Loops are implemented as compiler-managed templates of jumps. – chrylis -cautiouslyoptimistic- Oct 09 '13 at 17:39
  • Where did you find this information? I would like to show my teacher from a specific source. – REGAL Oct 09 '13 at 17:40
  • @user2174407 This link is a source. But, you could compile and look at the bytecode yourself if you like. – Cruncher Oct 09 '13 at 17:40
  • 1
    @user2174407 Look at the `javap` program, specifically the `-c` option. – chrylis -cautiouslyoptimistic- Oct 09 '13 at 17:40
  • @user2174407 You could also follow this logic in explaining it to your teacher. This is a constructive proof. Showing how, given an arbitrary while loop, you can create a for loop. – Cruncher Oct 09 '13 at 17:42
  • 7
    @user2174407: If you're trying to prove to your teacher that they're equivalent at the level of byte-code, by all means show this response. But I'd imagine the tack your teacher is taking is more likely: "don'y use `for (; checkIsTrue; ) { ... }` when you could use `while (checkIsTrue) { ... }` for readability sake." – Andrew Coonce Oct 09 '13 at 18:08
  • @chrylis and all are syntatic sugar for GOTOs, that are really hated :) – woliveirajr Oct 09 '13 at 19:45
  • @woliveirajr GOTOs alone can't implement conditional jumps. You need a goto *and* an if statement for that. – luiscubal Oct 09 '13 at 20:13
  • This answer doesn't show that do-while loops can also be converted to for loops. – Peter Olson Oct 09 '13 at 21:19
  • 2
    @PeterOlson I've described how do-while can be converted to while and I've described how while can be converted to for. Hence, I've also described how do-while can be converted to for. – arshajii Oct 09 '13 at 21:21
  • @arshajii "Also note that the fun doesn't just end with loops: it's also possible to convert every loop into a recursive function and vice versa." Not quite; in languages without certain optimizations (tail call optimization in particular), converting a loop into a recursive function can cause the stack to overflow. – Lily Chung Oct 09 '13 at 22:43
  • @IstvanChung I was referring to the principle as opposed to specific implementations. In those languages it *is* still possible to convert loops to recursive functions that should in theory have the same behavior, we are just limited by the fact that we don't have an infinite stack. It's like comparing two "equivalent" algorithms: although one might 'fail' with a huge input in various ways, in theory their behaviors can still be the same. – arshajii Oct 10 '13 at 00:29
  • Just for fun, `for (INIT;COND;INC;) { BODY; }` can become this while loop: `{INIT; while (COND) { BODY; INC; } }` and `while (COND) { BODY; }` can become `if (COND) do { BODY; } while (COND);`. Thus, all loops are interchangeable either way. – 3Doubloons Oct 10 '13 at 00:30
  • 1
    @AlexBrault if `BODY` contains `continue;` then the `for` loop is not equivalent to the `while` loop (`INC` is evaluated in one case and not in the other). – Alok-- Oct 10 '13 at 00:51
  • @Alok: Good point. Surely there's some way to fix that, but I've had my fun. Let's call it "equivalent enough". Plus `continue` and `break` also mess with the `do while` equivalent – 3Doubloons Oct 10 '13 at 01:08
  • @arshajii True, but it seemed worth noting that there were real, tangible differences in practice - as opposed to between a `for` and a `while` loop. – Lily Chung Oct 10 '13 at 01:36
  • @IstvanChung Absolutely, I agree. I'll add that to the answer. – arshajii Oct 10 '13 at 01:38
  • @luiscubal Yes, I know.. was just making fun of the GOTO that appears after some conditional jump, or jump if zero, or any variation of it, because I asked sometime ago if there was any situation where only a GOTO would would worked, and was downvoted and closed because GOTO are really hated :-D – woliveirajr Oct 10 '13 at 03:36
  • Not sure all `for`s can be replaced with `while` in Java - if you use the `for (thing x : things)` there isn't a direct translation. (You could use an iterator in a `while` loop, but it's not quite the same.) Other languages handle this differently - e.g. C# uses the `foreach` keyword for this kind of thing so it's different - in that case `for` and `while` are indeed interchangeable because `for` doesn't have that alternate syntax. – Darrel Hoffman Oct 10 '13 at 05:24
  • 1
    @DarrelHoffman for-each is pure syntactic sugar. You could do the exact same thing using an iterator with a while loop. There is absolutely no distinction, ultimately. – arshajii Oct 10 '13 at 12:08
  • I stand corrected. The desugared version in this case is a LOT more code, however. Can't think of too many instances where you'd want to do it that way... – Darrel Hoffman Oct 11 '13 at 15:19
6

No, you can always rewrite a for loop as a while loop, and any while look as a for loop.

<init>
while (condition) {
...
<increment>
}

is equivalent to:

for (<init>; <condition>; <increment>) {
...
}
Oleksi
  • 12,947
  • 4
  • 56
  • 80
  • (For what it's worth, the debate seems to be over whether or not you can always use a for loop instead of a while loop, so showing how to convert the other way might be more useful for the OP) – Dennis Meng Oct 09 '13 at 17:27
  • 2
    @DennisMeng "equivalent to" is logically a bi-conditional (<==>). Meaning that it goes BOTH ways. Otherwise the correct wording would be "implies", or "if this works, then this also works" – Cruncher Oct 09 '13 at 17:33
  • @Cruncher I guess the better statement would have been "swapping the order of the two would make it easier to follow wrt to the OP's debate with his teacher", instead of "showing how to convert...more useful for the OP". – Dennis Meng Oct 09 '13 at 17:36
  • What if `` contains a few lines of code requiring calling functions, declaring multiple different variables or instantiating classes? The only restriction I can think of is that you may not able to place anything you want in the section of the `for` loop. (though you can put that section before `for` loop and omit it inside, but I don't know, if this counts :)) – Spook Feb 18 '14 at 06:06
  • If requires several lines, you have to group those lines in a function and just call the function. – Oleksi Feb 18 '14 at 19:35
2

The other answers have already covered the equivalence between a while loop and a for loop. That is,

while(<expr>) {
  <body>
}

is equivalent to

for(;<expr>;) {
}

Note that a similar reduction can be done with a do-while loop. Any do-while loop

do {
  <body>
} while(<expr>);

is functionally equivalent to

for (boolean firstIter = true; firstIter || <expr>; firstIter = false) {
  <body>
}
Peter Olson
  • 139,199
  • 49
  • 202
  • 242
  • +1. _Except_ this fails if `firstIter` already exists and is _used_ in `` and/or ``. – Joseph Quinsey Feb 12 '14 at 16:15
  • And back to the epoint, this is an example where a for loop should NOT be used. It is clear that for and while are interchangeable, the question was which one to use when. – Florian F Aug 31 '14 at 16:19
0

"Absolutely"? I'd say no. However a test after loop aka do-while in Java would require a pretty convoluted "for" condition. Which brings one back to the boolean absolute: the condition must evaluate true or false.

So while I cannot envisage a case when the compiler could not be manipulated into performing the correct logic, I can see in very short order where anyone maintaining your program might well want you stoned (or perhaps think you were already).

On a related note there is nothing you can do in Java that cannot be done in machine language. But there are lots and lots of really good reasons for not using machine language. Most of them apply equally for when you try to get "cute" writing your code. It's all fun and games until you're on the phone with an irate customer at 0300, or your boss, or both.

Terry
  • 911
  • 10
  • 26