4

First code snippet prints 2

public static void main(String args[]) throws Exception {  
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val = (a = b)[3];
    System.out.println( a [val  ] );
}

Second code snippet outputs 1

public static void main(String args[]) throws Exception {
    int[] a = { 1, 2, 3, 4 };
    int[] b = { 2, 3, 1, 0 };
    int val;
    System.out.println(a[val = ((a = b)[3])]);
}

What is going on?

output1

2nd output

Kumar Abhinav
  • 6,565
  • 2
  • 24
  • 35
  • 3
    wow ! what a weird syntax. what were you trying to do ? – Erran Morad Oct 11 '14 at 07:18
  • @BoratSagdiyev which java version you are using?I am attaching java screenshot.. – Kumar Abhinav Oct 11 '14 at 07:22
  • possible duplicate of [What are the rules for evaluation order in Java?](http://stackoverflow.com/questions/6800590/what-are-the-rules-for-evaluation-order-in-java) – Henry Oct 11 '14 at 07:25
  • @KumarAbhinav - I use jre 8. I can attach my code + output, but it wont be an answer. People might downvote. – Erran Morad Oct 11 '14 at 07:26
  • I get 2 for first snippet and 1 for second in jre 7. – Voicu Oct 11 '14 at 07:27
  • @BoratSagdiyev attached the screenshots,I am too using java7 in eclipse – Kumar Abhinav Oct 11 '14 at 07:29
  • @KumarAbhinav - Looks like some serial downvoter is downvoting without even reading the answers. I just deleted the comment + code I posted in the answer section. – Erran Morad Oct 11 '14 at 07:30
  • 1
    @BoratSagdiyev Wasn't the first line of your answer something like "This is not an answer..." – takendarkk Oct 11 '14 at 07:31
  • someone has tagged it as duplicate ,but rules for evaluation doesnt explain my doubt – Kumar Abhinav Oct 11 '14 at 07:32
  • @Takendarkk - yes. that is correct. But, I would never hold it against you if you told me that you downvoted me. Then...i'll serially downvote you...just kidding. – Erran Morad Oct 11 '14 at 07:32
  • @BoratSagdiyev Why would you post an answer that starts with "This is not an answer"? – takendarkk Oct 11 '14 at 07:33
  • @Takendarkk - could not post it as a comment. That is why. Chenqui. – Erran Morad Oct 11 '14 at 07:35
  • 1
    @Henry: I see that you marked this as a duplicate. However, I don't quite follow how this particular example is explained by Java's evaluation order rules. Would you mind spelling it out in an answer? Thanks. – NPE Oct 11 '14 at 07:35
  • @NPE see answer, the difference comes from the different evaluation order in the two snippets. – Henry Oct 11 '14 at 07:48

6 Answers6

2

The output is reasonable. Let's expand the two complicated lines into several separate statements. First snippet:

// This...
int val = (a = b)[3];
// Becomes...
a = b;
int val = a[3]; // 0

So printing a[val] will print a[0], which is now 2.

The second snippet is more complicated. The tricksy bit is that "the array we're indexing into" is evaluated before the rest of the side-effects. So:

// This...
System.out.println(a[val = ((a = b)[3])]);
// Becomes...
int[] tmp = a; // So tmp is { 1, 2, 3, 4 }
a = b;
val = a[3]; // 0
System.out.println(tmp[val]); // 1

JLS section 15.10.4 goes into more detail about this. The important parts here are:

At run time, evaluation of an array access expression behaves as follows:

  • First, the array reference expression is evaluated. If this evaluation completes abruptly [...] evaluated.
  • Otherwise, the index expression is evaluated. If this evaluation completes abruptly [...]
  • Otherwise, if the value of the array reference expression is null [...]
  • Otherwise, the value of the array reference expression indeed refers to an array. If the value of the index expression is less than zero [...]
  • Otherwise, the result of the array access is the variable of type T, within the array, selected by the value of the index expression.
Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Someone mentioned that the output is different in JRE 8. I haven't verified this myself, but is there any reason to expect this to behave differently across Java versions (or implementations)? – NPE Oct 11 '14 at 07:37
  • @NPE I tested it with Java 8. No difference. And I doubt there is any. – Seelenvirtuose Oct 11 '14 at 07:39
  • @NPE: Nope - and it gives 1 for me under JRE 8. I suspect a diagnostic error on the part of the person reporting a value of 2. – Jon Skeet Oct 11 '14 at 07:39
  • @NPE Can output vary for a JLS specification across different compiler versions for a single vendor? – Kumar Abhinav Oct 11 '14 at 07:40
  • @KumarAbhinav: Not sure what you mean, but given that Borat appears to have removed his comment claiming that the second snippet produces 2 as well, my guess is that he hadn't recompiled, or something like that. – Jon Skeet Oct 11 '14 at 07:42
  • 2
    @NPE: If Borat's deleted answer is anything to go by, the problem was that he ran snippet 1 and then snippet 2... by which time `a` already referred to a different array. Definite red herring. – Jon Skeet Oct 11 '14 at 07:44
  • @JonSkeet Sir,it's an awesome analysis for Borat's comment – Kumar Abhinav Oct 11 '14 at 07:55
1

In the first code snippet the interesting part is

int val = (a = b)[3]

Here there are two assignments. The first one (a = b) will happen first and lets the variable a also reference the array that b refers to (note that the old array is not referenced anymore and thus is eligible to being garbage collected).

Afterwards you ask for the element on index 3. And that is the value "0". The output then asks for the element on index 0 in that array. And as you can see, this is the value "2". Remember that a now refers to the same array as b.

In the second code snippet you are doing all in the same line:

System.out.println(a[val = ((a = b)[3])]);

Although the assignments and indexing look the same, the major difference here is that you are accessing the array (referenced by a) before you reassign the variable.

So after all assignments are done, the variable val has the same value "0" and the variable a refers to the same array as b. But now the first element (index 0) in the old array will be looked up. And that is "1".

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
1

The relevant part of the Java Language specification (15.13.1. Run-Time Evaluation of Array Access) states:

An array access expression is evaluated using the following procedure: First, the array reference expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason and the index expression is not evaluated. Otherwise, the index expression is evaluated. If this evaluation completes abruptly, then the array access completes abruptly for the same reason.

The first snippet is the easy part: after the statement int val = (a = b)[3]; the array variable a points to the array { 2, 3, 1, 0 } taking the element at index 0 gives the answer 2.

In the second snippet the a is evaluated before the index expression, so a points to the array { 1, 2, 3, 4 }. Taking the element at index 0 this time gives the answer 1.

Henry
  • 42,982
  • 7
  • 68
  • 84
1

first:

int[] a = { 1, 2, 3, 4 };
int[] b = { 2, 3, 1, 0 };

int val = (a = b)[3];
/**
* a=b => a = { 2, 3, 1, 0 };
* val = a[3] = 0;
* a[val] => a[0] =>2;
**/

System.out.println( a [val  ] );  //2

second:

int[] a = { 1, 2, 3, 4 };
int[] b = { 2, 3, 1, 0 };
int val;
System.out.println(a[val = ((a = b)[3])]);
/**
* a[val = ((a = b)[3])]    
* => a[val=(b[3])]   val is not used here
* => a[b[3]] => a[0] => 1
**/
Vito
  • 1,080
  • 9
  • 19
0

there is two set of experssions:

A:

1. int val = (a = b)[3];
2. a [val]

and B:

1. a[val = ((a = b)[3])]

after executing A.1: a={2,3,1,0} and val=0 so a[val]=2

when executing B.1: a={1,2,3,4} and val=0 so a[val]=1

in B the (a=b) is a reference to {2,3,1,0} so (a=b)[3]=0 and val=0 and a is a reference to {1,2,3,4} (because the assignment does not complete yet) so a[0]=1

Farvardin
  • 5,336
  • 5
  • 33
  • 54
  • Someone mentioned that the output is different in JRE 8. I haven't verified this myself, but is there any reason to expect this to behave differently across Java versions (or implementations)? – NPE Oct 11 '14 at 07:38
  • It's not at all clear what you mean by "because the assignment doesn't complete yet". By the time the array is actually accessed, the assignment for `a = b` *has* completed... but the tricky bit is that it hadn't occurred when the evaluation determined which array was going to be accessed. There's a significant difference there. – Jon Skeet Oct 11 '14 at 07:42
  • @NPE I test it with java7 and java8 and the result is identical. – Farvardin Oct 11 '14 at 07:53
  • @طاهر the wordings of your answer may be misleading – Kumar Abhinav Oct 11 '14 at 08:14
0

So in the first example, b is assigned to a, val equals the 4th value of b, 0, and then we print the value with index 0, 2. You got this.

In the second example, as all operations are done in one time, a still kept its initial value when accessing the index 0, so 1 is printed. The second snippet is equivalent to :

int val = b[3];
System.out.println(a[val]);
a =b;
ToYonos
  • 16,469
  • 2
  • 54
  • 70