'How is if/while condition evaluated when we use assignments instead of comparison?

I discovered this surprising thing while learning OCA/OCP for Java.

Below is the first piece of code of which the if(test condition) part surprises me.

public class BooleanIf {
public static void main(String[] args) {
    boolean b = false;
    System.out.println(Boolean.valueOf(b = true));
    if (b = true)
        System.out.println("true");
    else
        System.out.println("false");
}

Now the output of this surprisingly is "true".

I learnt that there has to be a relational condition that returns true or false like if (a > b) or if (a != b) likewise.

I want to know how it is returning true for this case. Does it call Boolean.valueOf()?



Solution 1:[1]

= is assignment operator, == is comparison operator.

But

x = y

not only assigns value from y to variable x, but it also returns that value.

Thanks to that we can write code like (although it is not that common)

x = y = z = 1;
//equivalent of:
x = (y = (z = 1));

As you see 1 is first assigned to variable z, then expression z = z returns value 1 which can be assigned to variable y. Then again 1 is returned and assigned to variable x.

Because of that it is also possible to write code like if (b = true) where true is assigned to b and then expression b = true returns true, so we end up with if(true).

In other words if(b=true){...} is very similar to if(true){b=true; ..}, so it will always execute code from true branch.


BONUS: How to prevent this typo?

  • omit ==true and ==false parts.

    • In case of if(b==true) we can write if(b) since (b == true) will always give same result as already stored in b.
    • In case of if(b==false) we can write if(!b).
  • use Yoda conditions if(true == b){..} where value is used before/on left side and variable on right side of ==.
    Even if by mistake we will write = instead of == we will end up with true = b which will end up as compilation error since we can't assign anything to value like true (just like we can't compile 2=3; which would attempt to assign 3 to 2 which makes no sense). We can only assign values to variables.

Solution 2:[2]

this is not a very good practice

Boolean.valueOf(b = true), and you should avoid doing such, now regarding the question>

if (b = true) is the same as

b = true;
if (b)

therefore the condition is always met

analog to this.

if (b = false)

will be never ever executed...

ADditional information:

that kind of typos/mistakes are made by normally junior developers...

some when in the history of the development, it came a solution for that...

the so called JODA-Conditions(called like that as the Master JODA from stars-wars...)

so, the JODA-Conditions will be safe in this case since you can try to do:

if (true = b) {
        // code here
    }

but this will no compile since the complain:

The left-hand side of an assignment must be a variable,

the controversy is still open about how good idea is that, is the code more readable like that etc etc...,

Solution 3:[3]

Let's start by looking at the structure of an if statement:

if ( <boolean-expression> ) {
    ...
}

The <boolean-expression> can be any expression that evaluates to boolean. Most commonly, this is a logical expression, i.e. an expression with comparison operators and/or some logical operators, such as &&, ||, and !.

However, the expression could be a call to a method returning a boolean, for example:

if (list.isEmpty()) {
    ...
}

Next, let's look at an assignment expression. It is an expression with a side effect. The right side gets evaluated and assigned to the left side. The value of the assignment expression is the value of the variable after the assignment.

In your case, the assignment is b = true, so the value of the expression is true. Plugging it into the first part explains why you get the result that you see - b = true in

if (b = true) {
    ...
}

is a valid boolean expression returning true, so the code complies and runs correctly. A more common scenario uses an assignment to store the result for future reference, like this:

if (b = list.isEmpty()) {
    ...
}

This lets you refer to the result of list.isEmpty() outside of the conditional, without invoking the method again.

Note: Although situations exist when an assignment inside a conditional is a valid practice, it is not common, so one should heavily comment its use.

Solution 4:[4]

if expects an expression of type boolean.

A boolean variable has type ... boolean.

So, what might probably happen when you put a boolean variable behind an if?

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4 GhostCat