The Inspection Connection – Issue #2, Proposition Transformation

Boolean algebra can be difficult to reason about, which is why IntelliJ IDEA provides several inspections and intentions to simplify boolean expressions, improve readability and help make your code less prone to bugs. Here are just a few you may encounter while writing Java.

1. De Morgan’s Laws

De Morgan’s laws are (1) ¬a ∧ ¬b ≡ ¬(a ∨ b) and (2) ¬a ∨ ¬b ≡ ¬(a ∧ b). We can use these laws to transform boolean expressions programmatically, saving you the hassle of drawing a truth table to confirm your own good intuition.

By placing your cursor on line 2, then pressing Alt+Enter,w to select Replace ‘&&’ with ‘||’, IntelliJ IDEA will apply De Morgan’s first law, by first replacing conjunctions with disjunctions and negating the whole clause, leaving us:

As you can see, this may not always be the shortest or most natural form, so we can easily swap back and forth by between them by pressing Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z, or by repeating the inspection to apply De Morgan’s first law in reverse.

2. Rearranging control flow

IntelliJ IDEA provides two intentions for merging nested Ifs with conjunction and equivalent Ifs with disjunction, and two for separating them, via Split if and Extract if condition, respectively. For example, consider the following scenario:

By applying the first intention Merge nested ‘if’s, this can be reduced to:

Likewise, sequential ‘if’ conditions with identical bodies can be joined with disjunction.

By placing your cursor over the ‘i’ or ‘f’ on line #1 and applying the intention Merge sequential ‘if’s, this can be reduced to:

Now, if you want to break up a complex ‘if’ statement, you can place the cursor over a boolean expression, and apply the intention Extract if (…), where ‘…’ indicates the expression to be extracted.

Whichever disjunct your cursor is covering when the inspection is applied, that condition will be extracted into a new If statement and either nested inside the existing one or placed directly afterwards.

Keep in mind, if that if the condition contains a function call, this refactoring may alter the sequential structure of your program.

3. Flip Comparison

By reversing the traditional order of conditionals, Yoda notation claims two benefits: reducing null pointer errors and preventing accidental assignment. Many programmers follow this style in order to call attention to the boundary value:

However we can see that Yoda notation hides a null pointer that may potentially reappear later (in this case on line #4). The second motivation, that Yoda notation prevents ‘=’ where ‘==’ is intended, is demonstrated below.

In Java, there are very few cases where accidental assignment is also syntactically valid, and IntelliJ IDEA will detect those cases where assignments are used inside a condition. So we can safely swap Yoda conditions with the more traditional variation.

No matter which convention your code adopts, is important to use one consistently across your project. IntelliJ IDEA supports annotations for nullity inference, so the rationale behind Yoda notation in Java is less clear, but the choice is yours.

4. Avoiding negative conditionals

In Clean Code, Robert Martin writes, “Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives.” (Martin, [G29]). IntelliJ IDEA has three inspections to help you stay positive.

When conditionals are negative, this is a good indication that control flow can be refactored. When refactoring your code, you should apply the intention Invert If Condition. Notice how De Morgan’s law is implicitly used to refactor this clause.

IntelliJ IDEA can detect when a boolean method is always inverted, giving you the opportunity to rename these functions. In order to trigger a global inspection like this one, you will need to explicitly run it. You can find this inspection under Analyze|Inspect Code.

This warning can be resolved by clicking “Invert method” on the right hand side of the Inspection Results Window, under “Problem resolution”. IntelliJ IDEA will prompt us to rename the method and then remove all negated invocations across the scope of the inspection.

isAlwaysInverted

Similarly, the inspection boolean variable is always inverted will help discover negated variables within a class, and IntelliJ IDEA 13+ offers an inspection for detecting negatively named boolean variables, like disabled, hidden, or isNotChanged. You can enable this inspection under Inspections|Data flow issues.

This entry was posted in Tips & Tricks and tagged . Bookmark the permalink.

5 Responses to The Inspection Connection – Issue #2, Proposition Transformation

  1. Michael Glockenstein says:

    the first example in #3 repeats the code from #1 and does not show yoda style

  2. Alejandro Hdez. Angeles says:

    In the Merge sequential ‘if’s example, i call intentions but doesn’t appear the option of merging sequencial if’s, i’m using IntelliJ Idea 14 Preview

    • Breandan Considine says:

      Alejandro, sometimes intentions can be a little finicky – your cursor needs to be directly over one of the characters in if (. I’ve updated the Merge sequential ‘if’s example to reflect this and added a ticket to YouTrack to make Show Intention Actions a little more flexible (this seems to be a recurring issue). Gracias por los comentarios!

  3. Alejandro Hdez. Angeles says:

    The example:
    public boolean shortCircuitAnd(Boolean a, Boolean b) {
    if(a == false) { //a = false -> no error
    return false;
    }
    if(false == b) { //false = b -> compiler error
    return false;
    }

    return true;
    }

    should be:
    public boolean shortCircuitAnd(Boolean a, Boolean b) {
    if(a = false) { //a = false -> no error
    return false;
    }
    if(false = b) { //false = b -> compiler error
    return false;
    }

    return true;
    }

Leave a Reply

Your email address will not be published. Required fields are marked *