A Logical Story
Let me set the stage for today's blog. Logical variables have been part of MATLAB from the early days. They are particularly useful in constructs involved flow-of-control, such as if and while statements. But MATLAB, being an array-oriented language, needs to deal with expressions following if and while that might be any size, including empty matrices. But sometimes users get confused when two statements, seemingly the same, behave differently. The understanding lies in the intersection of scalar expansion, empty arrays, and logical operators, both short-circuit and elementwise.
Contents
Logical Operators, Scalar Expansion, and Empty Arrays
Recently on the MATLAB newsgroup, a user wondered why two statements, that seemed the same, didn't give the same answer. Let's take a look.
if 4 | [] disp('Must be true') end
Must be true
MATLAB evaluates
4 | []
as true.
However, swapping the order of the argument to | results in a false.
if [] | 4 disp('Must be true') else disp('Must be false') end
Must be false
How can that be?
Information to Help Unravel the Mystery
There are several concepts that might be helpful for understanding this mystery.
- Empty arrays evaluate to false for the purposes of if and while.
- The nonscalar | and & operators short-circuit in if and while expressions, but not otherwise.
- It's best to feed if and while scalar expressions. This means considering using the newer (MATLAB version 6.5) logical operators || and &&. These operators always short-circuit.
- Use reduction operations explicitly to reduce expressions to scalar. Examples of these operations include all and any.
Back to the Example
So, what's happening with this code?
if 4 | [] disp('Must be true') end % The 4 is nonzero and is unequivocally true, so that's the result you see.
Must be true
Inverting the statement requires evaluation of the [] first, then a scalar expansion occurs with the 4, yielding [] and that is false.
if [] | 4 disp('Must be true') else disp('Must be false') end
Must be false
If you were trying to debug this, however, you'd be tempted to evaluate
dbg = 4 | []
dbg = []
You would find dbg is empty (because of scalar expansion) and therefore, would be false according to most of the rules above. However, it does not account for the short-circuit nature of | and & in the if and while.
Notes and Recommendations
If you might have empties that you want to check for, check out isempty.
Use the || and && operators in expressions destined for if and while. These expressions behave consistently, meaning they always short-circuit, and are therefore easier to debug. They also force you to reduce your expression to a scalar and it is easier to see what a simple true or false means in the context of the flow-of-control. Do you have any other guidelines? Share them here.
- Category:
- Best Practice,
- Less Used Functionality,
- Robustness