gmanrocks
gmanrocks

Reputation: 281

Order of Operations with Logic in Java Confused

I have an order of operations problem from a quiz and the explanation is not exactly helpful. Here is the code:

package com.udayan.oca;

public class Test {
     public static void main(String [] args) {
         int a = 2;
         boolean res = false;
         res = a++ == 2 || --a == 2 && --a == 2;
         System.out.println(a);
     }
}

It says it prints 3 which it does because I tested that but I do not understand how. Here is their explanation:

a++ == 2 || --a == 2 && --a == 2;

[Given expression]. (a++) == 2 || --a == 2 && --a == 2;

[Postfix has got higher precedence than other operators].

(a++) == 2 || (--a) == 2 && (--a) == 2;

[After postfix, precedence is given to prefix].

((a++) == 2) || ((--a) == 2) && ((--a) == 2);

[== has higher precedence over && and ||].

((a++) == 2) || (((--a) == 2) && ((--a) == 2));

[&& has higher precedence over ||].

Let's start solving it: ((a++) == 2) || (((--a) == 2) && ((--a) == 2));

[a=2, res=false].

(2 == 2) || (((--a) == 2) && ((--a) == 2));

[a=3, res=false]. true || (((--a) == 2) && ((--a) == 2));

[a=3, res=false].

|| is a short-circuit operator, hence no need to evaluate expression on the right.

res is true and a is 3.

Yes, I understand short circuiting by the way so no need to explain that.

So here is my thinking however:

res = a++ == 2 || --a == 2 && --a == 2 ->
(((a++) == 2) || (((--a) == 2) && ((--a) == 2))) [a = 2]

(((a++) == 2) || ((**1** == 2) && ((--a) == 2))) [a = 1]

(((a++) == 2) || (**false** && (**0** == 2))) [a = 1] //short-circuits

(((a++) == 2) || **false**) [a = 1] //short circuits

(**false**) [a = 1]

???? Another point is that the answer key says to do a++ first then || next. a++ yah that makes sense. But I thought && is before ||.

Upvotes: 0

Views: 679

Answers (3)

Liam
Liam

Reputation: 68

From the Java Language Specification,

The conditional-or operator || operator is like | (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is false.

So, this is simpler than you think. res = a++ == 2 || --a == 2 && --a == 2; is evaluated like so:

res = ((a++ == 2) || ((--a == 2) && (--a == 2)));

a++ == 2? Post-increment means that a is read as 2. Then that expression is evaluated. 2 == 2, which is true. Short circuit means that the rest of the expression is never evaluated.

So, essentially all the above code does is res = a++ == 2;

I made a simple program to test this:

public class TestSOCode {
    public static void main(String [] args) {
        test1();
    }

    private static void test1(){
        int a = 2;
        boolean res = false;
        //res = a++ == 2 || --a == 2 && --a == 2;
        res = expression(a++, "One") || expression(--a, "Two") && expression(--a, "Three");
        System.out.println(res +" "+ a);
    }

    private static boolean expression(int i, String s){
        System.out.println(s+ " called with "+ i);
        return i == 2;
    }
}

This gives the result

One called with 2
true 3

UPDATE: After some discussion and research, I think there's been a misunderstanding of the difference between precedence and execution order when it comes to logical operators.

res = a++ == 2 || --a == 2 && --a == 2;

The above statement's precedence is worked out before it's evaluated. I won't go over the other precedence rules since it would complicate this answer, so I'll simplify it:

res = x || y && z;

&& takes precedence, so the expressions are grouped together like so:

res = x || (y && z);

As we can see, && takes priority, so the expressions to it's left and right are grouped together, then || is evalutated. The expression to it's left is x and the expression on it's right is (y && z) (I think we were both thinking that if && took priority, it would be like (a || b) && c so it would be evaluated first, but that's not how it works). If we want to see that this is in fact the case, we can modify the above code like so:

 res = expression(a = 8, "One") || expression(a = 16, "Two") && expression(a = 32, "Three");

This is equivalent to false || (false && false), but without any compiler interference with compile-time constants. The result of this is:

One called with 8
Two called with 16
false 16

First, the || is evaluated, then the left side of the &&. This returns false, and false && ? will always be false, so the third expression is not evaluated. But no precedence rules have been violated. I hope this has cleared up any confusion. If not, I'm happy to continue discussion in chat and update my answer. Because we know from the original code that if the first expression is true, the || returns true and short-circuits, we can say that a || b && c is not grouped together into (a || b) && c.

Upvotes: 2

phonemyatt
phonemyatt

Reputation: 1377

res = a++ == 2 || --a == 2 && --a == 2 (res is true)

1. a++ (post-increment, no) -> a = a + 1 -> it's still 2 -> when true -> it becomes 3
2. --a (pre-increment, right to left) -> a - 1 = a -> 1
3. --a (pre-increment, right to left) -> a - 1 = a -> 0 (its because of logical and, it never execute this part) 
4. == (equality, left to right) -> 2 == 2 || 1 == 2 && 0 == 2 -> true || false && false
5. && (logical and, left to right) -> false -> no more steps 
6. || (logical or, left to right) -> true -> go to 1.

// so take 3
// moral of the story is always use paranthesis
// op is correct for short-circuit 

Upvotes: 0

Saransh
Saransh

Reputation: 1

In the end when(((a++) == 2) || false) [a = 1] Is done then as the || operator having less precedence than ++ so here a will become 3 .. then it will print a=3 Though it's a short circuit operator still it have to do the ++ operator 1st.

Upvotes: 0

Related Questions