When writing methods that return booleans, many people make their
code much more complicated than it needs to be. For instance, suppose
you want a method that detects if a buggle has a wall both to its
left and its right. One way of doing this is as follows:

However, this is much more verbose than it needs to be. First of
all, study the inner conditional:

if (isWallToRight()) {
returntrue;
} else {
returnfalse;
}

If isWallToRight() returns true, then the conditional returns
true; if isWallToRight() returns false, then the conditional returns
false. So the above statement is equivalent to the single line.

return isWallToRight();

It is alway possible to replace the pattern if (E) {returntrue;} else {returnfalse;} by the
pattern returnE; for any boolean expression E. We expect you to make this
simplification in your code. Similarly, it is always possible to
replace the pattern if (E) {returnfalse;}
else
{returntrue;} by the pattern return
!E;.

This makes sense in terms of the contract for hasWallsOnBothSides() --- it should return true
if and only if there are walls to both the left and the right. But
how do we know when it's legal to make such a simplification?

Just as it is possible to simplify algebraic expressions by using
rules like cancellation, commutativity, associativity,
distributivity, etc., it is possible to simplify boolean expressions
and conditional statements by using rules. Here we present the rules
that you need to know.

In the following table, the patterns of boolean expressions in the
left column can always be replaced by the ones in the right column.
The notation boolExp
stands for any expression that evaluates to a boolean.

This pattern ...

... can be replaced by this simpler
pattern

boolExp == true

boolExp

boolExp == false

! boolExp

!!boolExp

boolExp

true
&&
boolExp

boolExp

boolExp
&&
true

boolExp

false
&&
boolExp

false

true
|| boolExp

true

false
|| boolExp

boolExp

boolExp||
false

boolExp

You should convince yourself that all of the above simplifications
are logically valid (i.e., substituting both true and false for boolExp makes the two columns have the same
value). Additionally, you should convince yourself that the
simplifications preserve errors and nontermination (i.e., if boolExp throws an exception or
gets stuck in an infinite loop, both columns still have the same
behavior.) In some cases, the "short-circuit" nature of && and || is critical for satisfying the second
criterion. This second criterion is more subtle than logical
validity, and fails for the following two logically valid
simplifications; for this reason, they are not included in the above
table:

boolExp&& false

false

boolExp
|| true

true

Note that each of the simplifications in the larger table makes
the expression shorter. So if you continue to apply the
simplifications, you will eventually reach a point where you can no
longer apply any more simplifications. Furthermore, it turns out that
no matter what order you apply the simplifications in, you will
eventually reach a unique shortest expression.

There are other important valid transformations that preserve
meaning but destroy the property of reaching a unique simplest
result. Here are some of these; the first two are known as
DeMorgan's laws:

(! boolExp1) || (! boolExp2)

! (boolExp1&& boolExp2)

(! boolExp1) && (! boolExp2)

! (boolExp1|| boolExp2)

boolExp1 || ((! boolExp1) && boolExp2)

boolExp1 || boolExp2

((!
boolExp1) && boolExp2) || boolExp1

boolExp1 || boolExp2

(! boolExp1) || (boolExp1 && boolExp2)

(! boolExp1) || boolExp2

(boolExp1 && boolExp2) || (! boolExp1)

(! boolExp1) || boolExp2

boolExp1 && ((! boolExp1) || boolExp2)

boolExp1 && boolExp2

((!
boolExp1) || boolExp2) && boolExp1

boolExp1 && boolExp2

(! boolExp1) && (boolExp1 || boolExp2)

(! boolExp1) && boolExp2

(boolExp1 || boolExp2) && (! boolExp1)

(! boolExp1) && boolExp2

You should verify that these simplifications are logically valid
and preserve error and non-termination semantics. To see that the
first rule destroys the property of reaching a unique shortest
expression, consider the expression

(! (!x)) || (! y)

Using the simplification that eliminates double negation, this can
be simplifed in one step to x || (!
y). But it can also be simplified by the first DeMorgan
simplification to ! ((! x) &&
y). Both of these expressions cannot be simplified any
further. There are similar examples involving the other rules.

Some of the above patterns may seem silly (you're probably saying
to yourself, "I would never write that!"). But even though you may
not write them yourself, they may show up in the results of some of
the simplifications of conditionals shown below. In this context you
would be expected to simplify them.

Now consider the following single transformation on conditional
statements that return boolean results:

if
(boolExp1) {returnboolExp2;
} else {returnboolExp3;
}

return
(boolExp1 && boolExp2)
|| ((! boolExp1)
&&
boolExp3);

You should convince yourself that this rule is logically valid and
preserves error and non-termination semantics. However, it does not
simplify the statement. Indeed, the result requires two evaluations
of boolExp1 where the
initial expression only required one! However, if at least one of
boolExp2 or boolExp3 is true or false, then the boolean expression
simplifications from above can lead to a simpler result. (Obviously,
similar results hold if boolExp1
is true or
false.) Below are some important instantiations of
this idea.