Loren on the Art of MATLAB

Turn ideas into MATLAB

Note

Loren on the Art of MATLAB has been archived and will not be updated.

Empty Arrays with Flow of Control and Logical Operators

After reading last week's post on calculating with empty arrays, one of my colleagues mentioned some other behaviors with empty arrays that have tripped him up in the past. Today I will discuss how empty arrays work in the contexts of flow of control expressions (both conditional and looping, i.e., if and while) and short-circuit operators (i.e., && and | |).

Contents

Empty Arrays in Flow of Control

Let me first start with plain empty arrays in flow of control situations. For example, what will this code do?

    E = [];
    if E
       disp('Empty is true')
    else
       disp('Empty is false')
    end

Readers who remember my comment on last week's blog will correctly guess that the empty expression for the if statement is treated as false. Why? The way I think about it is this. If I am looking for locations of some condition in an array, and I don't find them, I end up with an empty output. This very output is the kind of expression I am likely to want to use, somehow, in an if statement. Let's try it to be sure.

E = [];
if E
    disp('Empty is true')
else
    disp('Empty is false')
end
Empty is false

The situation gets a bit more complicated if there is a logical expression for the if or while statement that has an empty array as one of its elements. Let me show you what I mean. Paraphrasing the documentation,

 There are some conditions however under which while evaluates as true
 on an empty array. Two examples of this are
                  A = [];
                  while all(A), doSomething, end
                  while 1|A, doSomething, end

Let's see what's going on in each of these examples. In the first one, the function all is being called with an empty input. According to the second reference below (on empty arrays), the function all is one of the functions that returns a nonzero value for empty input. Let's see.

allE = all(E)
allEislogical = islogical(allE)
allE =
     1
allEislogical =
     1

The way I think about this is that there are no false values in E, hence the true result.

Empty Arrays with Logical Operators

The second expression involves an elementwise logical operator ( | ). In this case, the first part of the expression, 1, is true, so the second part, after the elementwise or, is never evaluated. So the fact that an empty result returns false never comes into play here. Why? Because & and | operators short-circuit when and only when they are in the context of if or while expressions. Otherwise, the elementwise operators do not short-circuit.

In contrast, the logical operators, && and | |, always short-circuit, regardless of context.

Short-circuit Logical Operators (| | and &&)

The next important idea to remember is that the short-circuit logical operators expect scalars as the inputs for the expressions. This means that an empty array, not being a scalar, may cause you some grief if you are unprepared for that situation. Let me show you what I mean. Compare the following 2 code snippets.

true || E
ans =
     1
try
    E || true
catch ME
    disp(ME.message)
end
Operands to the || and && operators must be convertible to logical scalar values.

In the second snippet, the expression E || true

produced an error, because E isn't a scalar value. Once the error occurs, the second operand is never evaluated. Contrast that with the snippet, where the first input evaluates to true. Short-circuiting then takes over and the second operand, which would cause an error in this context, is never evaluated.

Examples

Here are a few more code examples to help you see the patterns. Try to figure out the answers before reading the results.

if []
    disp('hello')
else
    disp('bye')
end
bye
true | []
ans =
     []
[] | true
ans =
     []
true || []
ans =
     1
try
    [] || true
catch ME
    disp(ME.message)
end
Operands to the || and && operators must be convertible to logical scalar values.
if true | []
    disp('hello')
else
    disp('bye')
end
hello
if [] | true
    disp('hello')
else
    disp('bye')
end
bye
if true || []
    disp('hello')
else
    disp('bye')
end
hello
try
    if [] || true
        disp('hello')
    else
        disp('bye')
    end
catch ME
    disp(ME.message)
end
Operands to the || and && operators must be convertible to logical scalar values.

References

Here are a bunch of references to the MATLAB documentation where all of this information is covered.

Empty Thoughts?

The behaviors with empties in MATLAB are, I believe, consistent and useful. Nonetheless, the behaviors have lots of details to master and can be confusing. If you have any thoughts on the matter, please respond here.




Published with MATLAB® 7.9


  • print