ComparisonWithBooleanLiteral

Misconception:

To determine whether an expression evaluates to true or false, one must use a relational operator (== or !=) to compare with a boolean literal (true or false). Incorrect

To test whether an expression is true or false, one must compare it to true or to false

Correct

To test whether an expression is true or false, one can just use it

CorrectionHere is what's right.

Such a comparison is entirely unnecessary.

if (CONDITION == true) {
...
}

This can be simplified to:

if (CONDITION) {
...
}

This applies to all uses of equality operators on boolean literals:

ExpressionEquivalent Simplified Expression
e == truee
e == false!e
e != true!e
e != falsee

Note that e is not just syntactic sugar for e==true. Indeed, if a programmer writes e==true, a compiler will convert that to e. Moreover, if e on its own would somehow be a convenient shortcut for e==true, then one would have to convert e==true to (e==true)==true, ad infinitum.

The following two expression trees illustrate this point: the simpler tree (with just the stop node) actually appears within the more complicated tree, and thus to deeply understand the complicated tree, one would need to understand the simpler tree: i.e., that it means to look up the value of variable stop, which is going to produce the exact value we are looking for.

Argumentation

One may want to ask a student with this misconception which of the following two code snippets they prefer, and why:

System.out.println(age + 0);
System.out.println(age);

Then one can ask which of the following they prefer:

System.out.println(stop == true);
System.out.println(stop);

Finally one can discuss what just writing age—and just writing stop—actually means.

One may also want to ask a student whether they would ever say “I am hungry is true” instead of just saying “I am hungry”. In a way, the former could be seen as a low-level statement, where one is concerned about “hungry” being a variable, while the latter is a higher-level statement, where “hungry” just means what it usually means.

While in our experience the above arguments do not always lead to a change in practice or attitude (i.e., students might continue to write explicit comparisons), we believe they help to provide a deeper understanding of expressions.

OriginWhere could this misconception come from?

This misconception may go back to textbooks and instructors using the term condition to describe what goes between the parentheses of conditional statments and loops.

if (CONDITION) { ... }
while (CONDITION) { ... }
for (...; CONDITION; ...) { ... }

Students may thus assume that a condition is a separate syntactic construct, and is different from an expression. This may include assumptions that a condition must including a comparison, or that it must test whether a variable contains a specific value, or even that only a small number of very specific conditions are possible (i.e., that conditions cannot be arbitrarily composed the way expressions can be).

This misconception may also be enabled by explanations like the following (from Section 2.13 “Making choices: the conditional statement” in Objects First with Java):

if (perform some test that gives a true or false result) {
...
} else {
...
}

Here, the wording “perform some test” may make students believe that the condition is not just an expression, but a special kind of constructs (a test) that possibly requires some testing operator (e.g., ==). The wording “a true or false result” may make students believe that they have to explicitly include true or false in the condition.

Note that this misconception is pretty much equivalent to the existing PMD Java design rule SimplifyBooleanExpressions. Thus, even professional developers seem to hold it.

SymptomsHow do you know your students might have this misconception?

We observed two kinds of symptoms: specific patterns in code, and specific explanations.

Code Patterns

In the following examples, assume that CONDITION is some expression of type boolean (e.g., isHappy, i < length, o != null, pacman.isHungry(), or a && b).

Condition

if (CONDITION == true) {
...
}

Return

return CONDITION == true; // or return (CONDITION == true);

Assignment

boolean b = CONDITION == true;

Assignment, with negation

boolean b = CONDITION != true;

Explanations

One explanation we observed was that a condition like stop == true was considered to be more explicit, and thus more easily understandable, than the equivalent condition stop. The reason given was that stop == true would show that the program would go check whether the variable stop contained the value true, while the expression stop would not be as descriptive.

This explanation may imply a possible NoAtomicExpression misconception (i.e., that a variable name in isolation is not understood to be an expression).

ValueHow can you build on this misconception?

This misconception provides an opportunity to discuss that conditions are expressions (expressions of type boolean). According to the Java Language Specification “Boolean expressions determine the control flow in several kinds of statements”.

Moreover, it provides an opportunity to a discuss the power of composition, and how expressions can be composed of all kinds of subexpressions.