Why is this loop changed?












39















I just encountered this decompiled class file of my class:



MyClass



while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}


The while loop has been changed to a for loop in the class file:



Decompiled MyClass



for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}


Why has this loop been changed to a for?
I think it might be another way of code optimization by the compiler, I could be wrong.
I just wanted to know if it is, what advantages does a for loop provide over a while loop or other loop?

What is the category of such code optimizations?










share|improve this question




















  • 23





    Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

    – Hulk
    Dec 14 '18 at 11:02








  • 6





    @KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

    – T.J. Crowder
    Dec 14 '18 at 11:04






  • 8





    @KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

    – Dici
    Dec 14 '18 at 11:07






  • 13





    @KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

    – T.J. Crowder
    Dec 14 '18 at 11:12






  • 8





    OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

    – ach
    Dec 14 '18 at 13:42
















39















I just encountered this decompiled class file of my class:



MyClass



while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}


The while loop has been changed to a for loop in the class file:



Decompiled MyClass



for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}


Why has this loop been changed to a for?
I think it might be another way of code optimization by the compiler, I could be wrong.
I just wanted to know if it is, what advantages does a for loop provide over a while loop or other loop?

What is the category of such code optimizations?










share|improve this question




















  • 23





    Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

    – Hulk
    Dec 14 '18 at 11:02








  • 6





    @KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

    – T.J. Crowder
    Dec 14 '18 at 11:04






  • 8





    @KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

    – Dici
    Dec 14 '18 at 11:07






  • 13





    @KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

    – T.J. Crowder
    Dec 14 '18 at 11:12






  • 8





    OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

    – ach
    Dec 14 '18 at 13:42














39












39








39


2






I just encountered this decompiled class file of my class:



MyClass



while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}


The while loop has been changed to a for loop in the class file:



Decompiled MyClass



for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}


Why has this loop been changed to a for?
I think it might be another way of code optimization by the compiler, I could be wrong.
I just wanted to know if it is, what advantages does a for loop provide over a while loop or other loop?

What is the category of such code optimizations?










share|improve this question
















I just encountered this decompiled class file of my class:



MyClass



while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}


The while loop has been changed to a for loop in the class file:



Decompiled MyClass



for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}


Why has this loop been changed to a for?
I think it might be another way of code optimization by the compiler, I could be wrong.
I just wanted to know if it is, what advantages does a for loop provide over a while loop or other loop?

What is the category of such code optimizations?







java loops optimization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 14 '18 at 15:06









Boann

36.7k1288121




36.7k1288121










asked Dec 14 '18 at 11:00









KumarAnkitKumarAnkit

332413




332413








  • 23





    Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

    – Hulk
    Dec 14 '18 at 11:02








  • 6





    @KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

    – T.J. Crowder
    Dec 14 '18 at 11:04






  • 8





    @KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

    – Dici
    Dec 14 '18 at 11:07






  • 13





    @KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

    – T.J. Crowder
    Dec 14 '18 at 11:12






  • 8





    OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

    – ach
    Dec 14 '18 at 13:42














  • 23





    Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

    – Hulk
    Dec 14 '18 at 11:02








  • 6





    @KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

    – T.J. Crowder
    Dec 14 '18 at 11:04






  • 8





    @KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

    – Dici
    Dec 14 '18 at 11:07






  • 13





    @KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

    – T.J. Crowder
    Dec 14 '18 at 11:12






  • 8





    OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

    – ach
    Dec 14 '18 at 13:42








23




23





Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

– Hulk
Dec 14 '18 at 11:02







Hard to tell from source code along, but it might just be a choice of the decompiler to show you this version. Note that a decompiler has to "guess" a bit - it chooses one possible source code that might lead to the given bytecode.

– Hulk
Dec 14 '18 at 11:02






6




6





@KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

– T.J. Crowder
Dec 14 '18 at 11:04





@KumarAnkit - No necessarily optimization, no. There isn't a one-to-one relationship between source constructs and bytecode. That's what Hulk means when he/she says "a decompiler has to 'guess' a bit."

– T.J. Crowder
Dec 14 '18 at 11:04




8




8





@KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

– Dici
Dec 14 '18 at 11:07





@KumarAnkit what people are trying to explain is that maybe there's no optimization at all. Try translating a hindi (or whatever is your regional dialect) sentence in english using Google translate, and then back to hindi. You'll be lucky if it's the same sentence than at the beginning. Here it's the same thing, got it?

– Dici
Dec 14 '18 at 11:07




13




13





@KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

– T.J. Crowder
Dec 14 '18 at 11:12





@KumarAnkit - for (and while, etc.) don't exist at the bytecode level. It's jump instructions, assignments, etc. One decompiler might look at some bytecode and say "that looks like a for" while another might look at it and say "that looks like a while". "So, does it mean these loops are identical at the byte-code level?" Not necessarily. If you compile the code output by a decompiler, you don't necessarily end up with identical bytecode. In fact, I suspect you rarely would.

– T.J. Crowder
Dec 14 '18 at 11:12




8




8





OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

– ach
Dec 14 '18 at 13:42





OP must be hiding something from us. The two snippets are not equivalent. The first one will never update i once it's equal to zero, so it may set the value of colArr multiple times in a reasonable scenario. The second one will update colArr only once.

– ach
Dec 14 '18 at 13:42












4 Answers
4






active

oldest

votes


















44














In this situation changing while() to for() is not an optimization. There is simply no way to know from bytecode which one was used in a source code.



There are many situations when:



while(x)


is the same as:



for(;x;)


Suppose we have a three similar java applications - one with while() statement, and two with corresponting for(). First for() with stopping criterion only like in the standard while(), and second for() also with iterator declaration and incrementation.



APPLICATION #1 - SOURCE



public class While{
public static void main(String args) {
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
}
}


APPLICATION #2 - SOURCE



public class For{
public static void main(String args) {
int i = 0;
for(; i<5 ;){
System.out.println(i);
i++;
}
}
}


APPLICATION #3 - SOURCE



public class For2{
public static void main(String args) {
for(int i=0;i<5;i++){
System.out.println(i);
}
}
}


If we compile all of them we have got:



APPLICATION #1 - BYTECODE



public class While {
public While();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #2 - BYTECODE



public class For {
public For();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #3 - BYTECODE



public class For2 extends java.lang.Object{
public For2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return

}


So you can see, there is no difference associated with for and while usage.






share|improve this answer





















  • 3





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











  • The bytecode will simply have a GOTO.

    – Jörg W Mittag
    Dec 14 '18 at 13:44






  • 1





    @Dici I've put a sample for better explanation.

    – dgebert
    Dec 14 '18 at 15:10











  • @dgebert +1. :p

    – Dici
    Dec 14 '18 at 19:31






  • 4





    I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

    – mtraceur
    Dec 14 '18 at 21:06



















14














As others have already pointed out: The decompiler (usually) cannot distinguish between different source codes that result in the same byte code.



Unfortunately, you did not provide the full code of the method. So the following contains some guesses about where and how this loop appears inside a method (and these guesses might, to some extent, distort the result).



But let's have a look at some roundtrips here. Consider the following class, containing methods with both versions of the code that you posted:



import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;

public class DecompileExample {

public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}
}

public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}


Compiling it with



javac DecompileExample.java -g:none


will create the corresponding class file. (Note: The -g:none parameter will cause the compiler to omit all debug information. The debug information might otherwise be used by the decompiler to reconstruct a more verbatim version of the original code, particularly, including the original variable names)



Now looking at the byte code of both methods, with



javap -c DecompileExample.class


will yield the following:



  public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return


and



  public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}


(There is a small difference: The String colArr = null is translated into an



aconst null
astore_3


at the beginning of the second version. But this is one of the aspects that is related to parts of the code that you have omitted in the question).



You did not mention which one you are using, but the JD-GUI decompiler from http://jd.benow.ca/ decompiles this into the following:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;

public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}

public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}


You can see that the code is the same for both cases (at least regarding the loop - there one more is a difference regarding the "dummy variables" that I had to introduce in order to compile it, but this is unrelated to the question, so to speak).



The tl;dr message is clear:



Different source codes can be compiled into the same byte code. Consequently, the same byte code can be decompiled into different source codes. But every decompiler has to settle for one version of the source code.



(A side note: I was a bit surprised to see that when compiling without -g:none (that is, when the debug information is retained), JD-GUI even somehow manages to reconstruct that the first one used a while-loop and the second one used a for-loop. But in general, and when the debug information is omitted, this is simply no longer possible).






share|improve this answer


























  • I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

    – KumarAnkit
    Dec 14 '18 at 12:45













  • @KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

    – Marco13
    Dec 14 '18 at 12:53











  • +1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

    – mtraceur
    Dec 14 '18 at 21:08











  • @mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

    – Marco13
    Dec 14 '18 at 22:05



















6














That's basically because of the nature of bytecode. Java bytecode is something like assembly language, so there are no such things as for and while loop, there is simply jump instruction: goto. So there may be no difference between while and for loop, Both can be compiled to similar code and decompiler is just making guess.






share|improve this answer





















  • 3





    While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

    – Dici
    Dec 14 '18 at 11:11



















5














Both the for loop and the while loop code segments can be translated into similar machine code. After that when de-compiling the de-compiler has to pick one of the two possible scenarios.



I guess that is what's happening here.



simply:



compile(A) -> C

compile(B) -> C


So when you are given C, then there should be a guess to pick A or B






share|improve this answer





















  • 4





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53778436%2fwhy-is-this-loop-changed%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























4 Answers
4






active

oldest

votes








4 Answers
4






active

oldest

votes









active

oldest

votes






active

oldest

votes









44














In this situation changing while() to for() is not an optimization. There is simply no way to know from bytecode which one was used in a source code.



There are many situations when:



while(x)


is the same as:



for(;x;)


Suppose we have a three similar java applications - one with while() statement, and two with corresponting for(). First for() with stopping criterion only like in the standard while(), and second for() also with iterator declaration and incrementation.



APPLICATION #1 - SOURCE



public class While{
public static void main(String args) {
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
}
}


APPLICATION #2 - SOURCE



public class For{
public static void main(String args) {
int i = 0;
for(; i<5 ;){
System.out.println(i);
i++;
}
}
}


APPLICATION #3 - SOURCE



public class For2{
public static void main(String args) {
for(int i=0;i<5;i++){
System.out.println(i);
}
}
}


If we compile all of them we have got:



APPLICATION #1 - BYTECODE



public class While {
public While();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #2 - BYTECODE



public class For {
public For();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #3 - BYTECODE



public class For2 extends java.lang.Object{
public For2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return

}


So you can see, there is no difference associated with for and while usage.






share|improve this answer





















  • 3





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











  • The bytecode will simply have a GOTO.

    – Jörg W Mittag
    Dec 14 '18 at 13:44






  • 1





    @Dici I've put a sample for better explanation.

    – dgebert
    Dec 14 '18 at 15:10











  • @dgebert +1. :p

    – Dici
    Dec 14 '18 at 19:31






  • 4





    I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

    – mtraceur
    Dec 14 '18 at 21:06
















44














In this situation changing while() to for() is not an optimization. There is simply no way to know from bytecode which one was used in a source code.



There are many situations when:



while(x)


is the same as:



for(;x;)


Suppose we have a three similar java applications - one with while() statement, and two with corresponting for(). First for() with stopping criterion only like in the standard while(), and second for() also with iterator declaration and incrementation.



APPLICATION #1 - SOURCE



public class While{
public static void main(String args) {
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
}
}


APPLICATION #2 - SOURCE



public class For{
public static void main(String args) {
int i = 0;
for(; i<5 ;){
System.out.println(i);
i++;
}
}
}


APPLICATION #3 - SOURCE



public class For2{
public static void main(String args) {
for(int i=0;i<5;i++){
System.out.println(i);
}
}
}


If we compile all of them we have got:



APPLICATION #1 - BYTECODE



public class While {
public While();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #2 - BYTECODE



public class For {
public For();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #3 - BYTECODE



public class For2 extends java.lang.Object{
public For2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return

}


So you can see, there is no difference associated with for and while usage.






share|improve this answer





















  • 3





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











  • The bytecode will simply have a GOTO.

    – Jörg W Mittag
    Dec 14 '18 at 13:44






  • 1





    @Dici I've put a sample for better explanation.

    – dgebert
    Dec 14 '18 at 15:10











  • @dgebert +1. :p

    – Dici
    Dec 14 '18 at 19:31






  • 4





    I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

    – mtraceur
    Dec 14 '18 at 21:06














44












44








44







In this situation changing while() to for() is not an optimization. There is simply no way to know from bytecode which one was used in a source code.



There are many situations when:



while(x)


is the same as:



for(;x;)


Suppose we have a three similar java applications - one with while() statement, and two with corresponting for(). First for() with stopping criterion only like in the standard while(), and second for() also with iterator declaration and incrementation.



APPLICATION #1 - SOURCE



public class While{
public static void main(String args) {
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
}
}


APPLICATION #2 - SOURCE



public class For{
public static void main(String args) {
int i = 0;
for(; i<5 ;){
System.out.println(i);
i++;
}
}
}


APPLICATION #3 - SOURCE



public class For2{
public static void main(String args) {
for(int i=0;i<5;i++){
System.out.println(i);
}
}
}


If we compile all of them we have got:



APPLICATION #1 - BYTECODE



public class While {
public While();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #2 - BYTECODE



public class For {
public For();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #3 - BYTECODE



public class For2 extends java.lang.Object{
public For2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return

}


So you can see, there is no difference associated with for and while usage.






share|improve this answer















In this situation changing while() to for() is not an optimization. There is simply no way to know from bytecode which one was used in a source code.



There are many situations when:



while(x)


is the same as:



for(;x;)


Suppose we have a three similar java applications - one with while() statement, and two with corresponting for(). First for() with stopping criterion only like in the standard while(), and second for() also with iterator declaration and incrementation.



APPLICATION #1 - SOURCE



public class While{
public static void main(String args) {
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
}
}


APPLICATION #2 - SOURCE



public class For{
public static void main(String args) {
int i = 0;
for(; i<5 ;){
System.out.println(i);
i++;
}
}
}


APPLICATION #3 - SOURCE



public class For2{
public static void main(String args) {
for(int i=0;i<5;i++){
System.out.println(i);
}
}
}


If we compile all of them we have got:



APPLICATION #1 - BYTECODE



public class While {
public While();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #2 - BYTECODE



public class For {
public For();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return
}


APPLICATION #3 - BYTECODE



public class For2 extends java.lang.Object{
public For2();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String);
Code:
0: iconst_0
1: istore_1
2: iload_1
3: iconst_5
4: if_icmpge 20
7: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_1
11: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
14: iinc 1, 1
17: goto 2
20: return

}


So you can see, there is no difference associated with for and while usage.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 23 '18 at 21:04

























answered Dec 14 '18 at 11:08









dgebertdgebert

732513




732513








  • 3





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











  • The bytecode will simply have a GOTO.

    – Jörg W Mittag
    Dec 14 '18 at 13:44






  • 1





    @Dici I've put a sample for better explanation.

    – dgebert
    Dec 14 '18 at 15:10











  • @dgebert +1. :p

    – Dici
    Dec 14 '18 at 19:31






  • 4





    I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

    – mtraceur
    Dec 14 '18 at 21:06














  • 3





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12











  • The bytecode will simply have a GOTO.

    – Jörg W Mittag
    Dec 14 '18 at 13:44






  • 1





    @Dici I've put a sample for better explanation.

    – dgebert
    Dec 14 '18 at 15:10











  • @dgebert +1. :p

    – Dici
    Dec 14 '18 at 19:31






  • 4





    I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

    – mtraceur
    Dec 14 '18 at 21:06








3




3





Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

– Dici
Dec 14 '18 at 11:12





Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

– Dici
Dec 14 '18 at 11:12













The bytecode will simply have a GOTO.

– Jörg W Mittag
Dec 14 '18 at 13:44





The bytecode will simply have a GOTO.

– Jörg W Mittag
Dec 14 '18 at 13:44




1




1





@Dici I've put a sample for better explanation.

– dgebert
Dec 14 '18 at 15:10





@Dici I've put a sample for better explanation.

– dgebert
Dec 14 '18 at 15:10













@dgebert +1. :p

– Dici
Dec 14 '18 at 19:31





@dgebert +1. :p

– Dici
Dec 14 '18 at 19:31




4




4





I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

– mtraceur
Dec 14 '18 at 21:06





I like this answer: I think the demonstration can be improved by moving the i++ into the for-loop to make: for(; i<5 ; i++){. That way you can show that either way, the bytecode puts the iinc at the end of the loop body at the bytecode level, and so the decompiler can't always tell if the i++ goes into the last field of the for loop or as the last statement in the loop body.

– mtraceur
Dec 14 '18 at 21:06













14














As others have already pointed out: The decompiler (usually) cannot distinguish between different source codes that result in the same byte code.



Unfortunately, you did not provide the full code of the method. So the following contains some guesses about where and how this loop appears inside a method (and these guesses might, to some extent, distort the result).



But let's have a look at some roundtrips here. Consider the following class, containing methods with both versions of the code that you posted:



import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;

public class DecompileExample {

public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}
}

public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}


Compiling it with



javac DecompileExample.java -g:none


will create the corresponding class file. (Note: The -g:none parameter will cause the compiler to omit all debug information. The debug information might otherwise be used by the decompiler to reconstruct a more verbatim version of the original code, particularly, including the original variable names)



Now looking at the byte code of both methods, with



javap -c DecompileExample.class


will yield the following:



  public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return


and



  public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}


(There is a small difference: The String colArr = null is translated into an



aconst null
astore_3


at the beginning of the second version. But this is one of the aspects that is related to parts of the code that you have omitted in the question).



You did not mention which one you are using, but the JD-GUI decompiler from http://jd.benow.ca/ decompiles this into the following:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;

public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}

public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}


You can see that the code is the same for both cases (at least regarding the loop - there one more is a difference regarding the "dummy variables" that I had to introduce in order to compile it, but this is unrelated to the question, so to speak).



The tl;dr message is clear:



Different source codes can be compiled into the same byte code. Consequently, the same byte code can be decompiled into different source codes. But every decompiler has to settle for one version of the source code.



(A side note: I was a bit surprised to see that when compiling without -g:none (that is, when the debug information is retained), JD-GUI even somehow manages to reconstruct that the first one used a while-loop and the second one used a for-loop. But in general, and when the debug information is omitted, this is simply no longer possible).






share|improve this answer


























  • I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

    – KumarAnkit
    Dec 14 '18 at 12:45













  • @KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

    – Marco13
    Dec 14 '18 at 12:53











  • +1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

    – mtraceur
    Dec 14 '18 at 21:08











  • @mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

    – Marco13
    Dec 14 '18 at 22:05
















14














As others have already pointed out: The decompiler (usually) cannot distinguish between different source codes that result in the same byte code.



Unfortunately, you did not provide the full code of the method. So the following contains some guesses about where and how this loop appears inside a method (and these guesses might, to some extent, distort the result).



But let's have a look at some roundtrips here. Consider the following class, containing methods with both versions of the code that you posted:



import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;

public class DecompileExample {

public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}
}

public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}


Compiling it with



javac DecompileExample.java -g:none


will create the corresponding class file. (Note: The -g:none parameter will cause the compiler to omit all debug information. The debug information might otherwise be used by the decompiler to reconstruct a more verbatim version of the original code, particularly, including the original variable names)



Now looking at the byte code of both methods, with



javap -c DecompileExample.class


will yield the following:



  public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return


and



  public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}


(There is a small difference: The String colArr = null is translated into an



aconst null
astore_3


at the beginning of the second version. But this is one of the aspects that is related to parts of the code that you have omitted in the question).



You did not mention which one you are using, but the JD-GUI decompiler from http://jd.benow.ca/ decompiles this into the following:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;

public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}

public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}


You can see that the code is the same for both cases (at least regarding the loop - there one more is a difference regarding the "dummy variables" that I had to introduce in order to compile it, but this is unrelated to the question, so to speak).



The tl;dr message is clear:



Different source codes can be compiled into the same byte code. Consequently, the same byte code can be decompiled into different source codes. But every decompiler has to settle for one version of the source code.



(A side note: I was a bit surprised to see that when compiling without -g:none (that is, when the debug information is retained), JD-GUI even somehow manages to reconstruct that the first one used a while-loop and the second one used a for-loop. But in general, and when the debug information is omitted, this is simply no longer possible).






share|improve this answer


























  • I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

    – KumarAnkit
    Dec 14 '18 at 12:45













  • @KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

    – Marco13
    Dec 14 '18 at 12:53











  • +1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

    – mtraceur
    Dec 14 '18 at 21:08











  • @mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

    – Marco13
    Dec 14 '18 at 22:05














14












14








14







As others have already pointed out: The decompiler (usually) cannot distinguish between different source codes that result in the same byte code.



Unfortunately, you did not provide the full code of the method. So the following contains some guesses about where and how this loop appears inside a method (and these guesses might, to some extent, distort the result).



But let's have a look at some roundtrips here. Consider the following class, containing methods with both versions of the code that you posted:



import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;

public class DecompileExample {

public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}
}

public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}


Compiling it with



javac DecompileExample.java -g:none


will create the corresponding class file. (Note: The -g:none parameter will cause the compiler to omit all debug information. The debug information might otherwise be used by the decompiler to reconstruct a more verbatim version of the original code, particularly, including the original variable names)



Now looking at the byte code of both methods, with



javap -c DecompileExample.class


will yield the following:



  public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return


and



  public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}


(There is a small difference: The String colArr = null is translated into an



aconst null
astore_3


at the beginning of the second version. But this is one of the aspects that is related to parts of the code that you have omitted in the question).



You did not mention which one you are using, but the JD-GUI decompiler from http://jd.benow.ca/ decompiles this into the following:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;

public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}

public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}


You can see that the code is the same for both cases (at least regarding the loop - there one more is a difference regarding the "dummy variables" that I had to introduce in order to compile it, but this is unrelated to the question, so to speak).



The tl;dr message is clear:



Different source codes can be compiled into the same byte code. Consequently, the same byte code can be decompiled into different source codes. But every decompiler has to settle for one version of the source code.



(A side note: I was a bit surprised to see that when compiling without -g:none (that is, when the debug information is retained), JD-GUI even somehow manages to reconstruct that the first one used a while-loop and the second one used a for-loop. But in general, and when the debug information is omitted, this is simply no longer possible).






share|improve this answer















As others have already pointed out: The decompiler (usually) cannot distinguish between different source codes that result in the same byte code.



Unfortunately, you did not provide the full code of the method. So the following contains some guesses about where and how this loop appears inside a method (and these guesses might, to some extent, distort the result).



But let's have a look at some roundtrips here. Consider the following class, containing methods with both versions of the code that you posted:



import java.io.BufferedReader;
import java.io.IOException;
import java.util.regex.Pattern;

public class DecompileExample {

public static void methodA(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
if (i == 0) {
String colArr = line.split(Pattern.quote("|"));

} else {
i++;
}
}
}

public static void methodB(BufferedReader reader) throws IOException {
String line = null;
int i = 0;
for (String colArr = null; (line = reader.readLine()) != null; ++i) {
System.out.println("line: " + line);
if (i == 0) {
colArr = line.split(Pattern.quote("|"));
} else {
}
}
}
}


Compiling it with



javac DecompileExample.java -g:none


will create the corresponding class file. (Note: The -g:none parameter will cause the compiler to omit all debug information. The debug information might otherwise be used by the decompiler to reconstruct a more verbatim version of the original code, particularly, including the original variable names)



Now looking at the byte code of both methods, with



javap -c DecompileExample.class


will yield the following:



  public static void methodA(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aload_0
5: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
8: dup
9: astore_1
10: ifnull 61
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: new #4 // class java/lang/StringBuilder
19: dup
20: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
23: ldc #6 // String line:
25: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: aload_1
29: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
32: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
35: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
38: iload_2
39: ifne 55
42: aload_1
43: ldc #10 // String |
45: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
48: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
51: astore_3
52: goto 4
55: iinc 2, 1
58: goto 4
61: return


and



  public static void methodB(java.io.BufferedReader) throws java.io.IOException;
Code:
0: aconst_null
1: astore_1
2: iconst_0
3: istore_2
4: aconst_null
5: astore_3
6: aload_0
7: invokevirtual #2 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
10: dup
11: astore_1
12: ifnull 60
15: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
18: new #4 // class java/lang/StringBuilder
21: dup
22: invokespecial #5 // Method java/lang/StringBuilder."<init>":()V
25: ldc #6 // String line:
27: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload_1
31: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: iload_2
41: ifne 54
44: aload_1
45: ldc #10 // String |
47: invokestatic #11 // Method java/util/regex/Pattern.quote:(Ljava/lang/String;)Ljava/lang/String;
50: invokevirtual #12 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String;
53: astore_3
54: iinc 2, 1
57: goto 6
60: return
}


(There is a small difference: The String colArr = null is translated into an



aconst null
astore_3


at the beginning of the second version. But this is one of the aspects that is related to parts of the code that you have omitted in the question).



You did not mention which one you are using, but the JD-GUI decompiler from http://jd.benow.ca/ decompiles this into the following:



import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Pattern;

public class DecompileExample
{
public static void methodA(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
String arrayOfString = str.split(Pattern.quote("|"));
} else {
i++;
}
}
}

public static void methodB(BufferedReader paramBufferedReader)
throws IOException
{
String str = null;
int i = 0;
String arrayOfString = null;
while ((str = paramBufferedReader.readLine()) != null)
{
System.out.println("line: " + str);
if (i == 0) {
arrayOfString = str.split(Pattern.quote("|"));
}
i++;
}
}
}


You can see that the code is the same for both cases (at least regarding the loop - there one more is a difference regarding the "dummy variables" that I had to introduce in order to compile it, but this is unrelated to the question, so to speak).



The tl;dr message is clear:



Different source codes can be compiled into the same byte code. Consequently, the same byte code can be decompiled into different source codes. But every decompiler has to settle for one version of the source code.



(A side note: I was a bit surprised to see that when compiling without -g:none (that is, when the debug information is retained), JD-GUI even somehow manages to reconstruct that the first one used a while-loop and the second one used a for-loop. But in general, and when the debug information is omitted, this is simply no longer possible).







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 14 '18 at 14:50

























answered Dec 14 '18 at 12:41









Marco13Marco13

42k855108




42k855108













  • I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

    – KumarAnkit
    Dec 14 '18 at 12:45













  • @KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

    – Marco13
    Dec 14 '18 at 12:53











  • +1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

    – mtraceur
    Dec 14 '18 at 21:08











  • @mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

    – Marco13
    Dec 14 '18 at 22:05



















  • I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

    – KumarAnkit
    Dec 14 '18 at 12:45













  • @KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

    – Marco13
    Dec 14 '18 at 12:53











  • +1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

    – mtraceur
    Dec 14 '18 at 21:08











  • @mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

    – Marco13
    Dec 14 '18 at 22:05

















I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

– KumarAnkit
Dec 14 '18 at 12:45







I am using the IntelliJ IDEA, which uses the fernflower decompiler. Thanks for the elaborated answer.

– KumarAnkit
Dec 14 '18 at 12:45















@KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

– Marco13
Dec 14 '18 at 12:53





@KumarAnkit As indicated by the comments about the -g:none flag, the result does not only depend on the decompiler, but also on how the .class files are generated in the first place. (But I assume that IDEs will usually not omit the debug information - in the end, they are basically intended for retaining it in order to use it in some nice debugger UI)

– Marco13
Dec 14 '18 at 12:53













+1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

– mtraceur
Dec 14 '18 at 21:08





+1 I think you can make it more clear by more explicitly emphasizing how the i++ at the end of the source code's loop body and the ++i at the end of the for-loop declaration map to the same instructions at the end of the bytecode's loop body.

– mtraceur
Dec 14 '18 at 21:08













@mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

– Marco13
Dec 14 '18 at 22:05





@mtraceur Yes, more generally: I considered to make the initial code more "sensible", that is, actually do something sensible with i and the colArr. But at some point, this involved so many changes that I was afraid to bury the code that was posted originally under these changes. Not sure about the best solution for this. But if the question was updated with compileable code, I'd update the answer accordingly.

– Marco13
Dec 14 '18 at 22:05











6














That's basically because of the nature of bytecode. Java bytecode is something like assembly language, so there are no such things as for and while loop, there is simply jump instruction: goto. So there may be no difference between while and for loop, Both can be compiled to similar code and decompiler is just making guess.






share|improve this answer





















  • 3





    While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

    – Dici
    Dec 14 '18 at 11:11
















6














That's basically because of the nature of bytecode. Java bytecode is something like assembly language, so there are no such things as for and while loop, there is simply jump instruction: goto. So there may be no difference between while and for loop, Both can be compiled to similar code and decompiler is just making guess.






share|improve this answer





















  • 3





    While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

    – Dici
    Dec 14 '18 at 11:11














6












6








6







That's basically because of the nature of bytecode. Java bytecode is something like assembly language, so there are no such things as for and while loop, there is simply jump instruction: goto. So there may be no difference between while and for loop, Both can be compiled to similar code and decompiler is just making guess.






share|improve this answer















That's basically because of the nature of bytecode. Java bytecode is something like assembly language, so there are no such things as for and while loop, there is simply jump instruction: goto. So there may be no difference between while and for loop, Both can be compiled to similar code and decompiler is just making guess.







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 14 '18 at 13:46









Andrei Suvorkov

4,1574929




4,1574929










answered Dec 14 '18 at 11:09









Wojtek MlodzianowskiWojtek Mlodzianowski

308113




308113








  • 3





    While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

    – Dici
    Dec 14 '18 at 11:11














  • 3





    While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

    – Dici
    Dec 14 '18 at 11:11








3




3





While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

– Dici
Dec 14 '18 at 11:11





While true, I think a good answer should make an analysis of the actual byte code. I don't have the motivation to do it now so I'll stick to comments, but just sayin'

– Dici
Dec 14 '18 at 11:11











5














Both the for loop and the while loop code segments can be translated into similar machine code. After that when de-compiling the de-compiler has to pick one of the two possible scenarios.



I guess that is what's happening here.



simply:



compile(A) -> C

compile(B) -> C


So when you are given C, then there should be a guess to pick A or B






share|improve this answer





















  • 4





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12
















5














Both the for loop and the while loop code segments can be translated into similar machine code. After that when de-compiling the de-compiler has to pick one of the two possible scenarios.



I guess that is what's happening here.



simply:



compile(A) -> C

compile(B) -> C


So when you are given C, then there should be a guess to pick A or B






share|improve this answer





















  • 4





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12














5












5








5







Both the for loop and the while loop code segments can be translated into similar machine code. After that when de-compiling the de-compiler has to pick one of the two possible scenarios.



I guess that is what's happening here.



simply:



compile(A) -> C

compile(B) -> C


So when you are given C, then there should be a guess to pick A or B






share|improve this answer















Both the for loop and the while loop code segments can be translated into similar machine code. After that when de-compiling the de-compiler has to pick one of the two possible scenarios.



I guess that is what's happening here.



simply:



compile(A) -> C

compile(B) -> C


So when you are given C, then there should be a guess to pick A or B







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 14 '18 at 11:39









meowgoesthedog

9,20131226




9,20131226










answered Dec 14 '18 at 11:11









primeprime

4,75964275




4,75964275








  • 4





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12














  • 4





    Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

    – Dici
    Dec 14 '18 at 11:12








4




4





Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

– Dici
Dec 14 '18 at 11:12





Maybe you could put the actual bytecode of both snippets in your answer to prove your point :p it's the intuitive answer, but it doesn't mean it's right

– Dici
Dec 14 '18 at 11:12


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53778436%2fwhy-is-this-loop-changed%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Список кардиналов, возведённых папой римским Каликстом III

Deduzione

Mysql.sock missing - “Can't connect to local MySQL server through socket”