Kumar Abhinav
Kumar Abhinav

Reputation: 6665

Array assignment output behaves differently for two code snippets

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

Upvotes: 4

Views: 325

Answers (6)

Vito
Vito

Reputation: 1090

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
**/

Upvotes: 1

ToYonos
ToYonos

Reputation: 16833

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;

Upvotes: 0

Henry
Henry

Reputation: 43728

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.

Upvotes: 1

Seelenvirtuose
Seelenvirtuose

Reputation: 20608

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".

Upvotes: 1

Farvardin
Farvardin

Reputation: 5414

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

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1499760

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.

Upvotes: 2

Related Questions