4
public class Main
{
    public static void main(String[] args)
    {
        int a,b,c,d;
        a=1;b=2;
        a^=b^=a^=b;
        System.out.println(a+" "+b);
        c=1;d=2;
        c^=d;
        d^=c;
        c^=d;
        System.out.println(c+" "+d);
    }
}

I use a^b^=a^=b to swap a and b. However the output of this program is

0 1
2 1

I am a new one in Java, and I don't know why a is 0. Is it a bug of my java runtime environment? Or there are something special in Java I don't know? Here is java -version.

java version "1.7.0_65"
OpenJDK Runtime Environment (fedora-2.5.2.5.fc20-x86_64 u65-b17)
OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)

Sorry it's my first question on stack overflow ... if I forgot some rules, tell me please, thank you.

  • 2
    The third time you wrote it you wrote it differently. – keyser Oct 09 '14 at 12:29
  • 10
    My advice? Don't write code like this. It's an obfuscation code winner. Your goal should be to write as clearly as possible. – duffymo Oct 09 '14 at 12:30
  • 1
    I know it's not a good way to code, but I wonder what happened when I used a^=b^=a^=b. I don't think a good programmer will do it too. – Sweetdumpling Lin Oct 09 '14 at 12:31
  • 6
    It's perfectly "legal" code, from a compiler standpoint, but I've got 40 years of programming experience, 10 with Java, and I couldn't tell you what it means. **Don't do it.** – Hot Licks Oct 09 '14 at 12:32
  • If you really want to know what it means, refer to the [JLS](http://docs.oracle.com/javase/specs/jls/se7/html/index.html) and work it out. It would be a good "exercise" in deciphering cryptic code. – Hot Licks Oct 09 '14 at 12:34
  • Well, I know what it means. What I wonder what's the difference between what I do on a/b and c/d. It seems same but the answer is different. – Sweetdumpling Lin Oct 09 '14 at 12:36
  • 1
    I think the purpose of the example is to demonstrate that such complex expression can bite you in the butt. – Hot Licks Oct 09 '14 at 12:38
  • I gave this question a down-vote, since I feel this strays beyond the type of theoretical questions that are welcome here into the *not useful* category. I think we all agree such code won't be written "for real", so having various people chew over it for a while to see what it means doesn't seem like a great idea. – Duncan Jones Oct 09 '14 at 12:39
  • (BTW, though it's a cute parlor trick it's foolish/inefficient (and in a few odd cases dangerous) to use the old 3 XOR scheme to swap values, except in the very specific situation of assembly language when the number of registers is limited. Use a temp.) – Hot Licks Oct 09 '14 at 12:42
  • If you really want to do it in one line without temp variables, use a+=(b-(b=a)); – Nuri Tasdemir Oct 09 '14 at 12:50

2 Answers2

4

Let's simplify it together

int a = 1;
int b = 2;
a ^= (b ^= (a ^= b));
System.out.println(a + " " + b);

is the same as saying

int a = 1;
int b = 2;
int a_tmp = a;
a = a_tmp ^ (b ^= (a ^= b));
System.out.println(a + " " + b);

Your code is assuming that we process a ^= (b ^= (a ^= b)) before a ^= (b ^= (a ^= b)) but that's wrong. I don't really know where it will work. But as pointed by @duffymo don't try this at home.

Community
  • 1
  • 1
talex
  • 17,973
  • 3
  • 29
  • 66
  • Yep, *any* statement with multiple assignments is dangerous at best. And the "operator-equals" operators are doubly dangerous. – Hot Licks Oct 09 '14 at 12:44
0

Make sure you look at your order of operations. This may be what is happening:

true ^ true = false  
true ^ false = true 
false ^ true = true 
false ^ false = false

a^=b^=a^=b;

Work right to left: 0001 ^ 0010 ^ 0001 ^ 0010 take the first 2 farthest right 0001 ^ 0010 = 0011. Now keep moving left take your answer with the next element 0010 ^ 0011 = 0001 now move left one more time. 0001 ^ 0001 = 0000 so a = 0000 or 0.
Now take the b expression: 0010 ^ 0001 ^ 0010 now do the same thing right to left. 0001 ^ 0010 = 0011 now move to the left 0010 ^ 0011 = 0001 so b = 0001 or 1. So when you print a = 0000 or 0 and b = 0001 or 1. This is bitwise exclusive OR operations make sure to look at order of operations carefully.

brso05
  • 13,142
  • 2
  • 21
  • 40
  • Your explanation is wrong. You assume that the values of the variables haven't changed yet by putting in 0001 ^ 0010 ^ 0001 ^ 0010 as the expression to evaluate. But actually it is a ^ 0010 ^ 0001 ^ 0010. Because after the evaluation of the first xor 0001 ^ 0010 also changes a. So it no longer is 0001 but 0011 for the first variable in your statement. The OP is actually correct by expecting 2 and 1 as values (according to the specs). I will post an answer later with why the result is 0 and 1 instead. – Juru Oct 10 '14 at 06:43