Last week I presented a seemingly-innocent Matlab code snippet with several variants, and asked readers to speculate what its outcomes are, and why. Several readers were apparently surprised by the results. In today’s post, I offer my analysis of the puzzle.
The original code snippet was this:
function test try if (false) or (true) disp('Yaba'); else disp('Daba'); end catch disp('Doo!'); end end
With the following variants for the highlighted line #3:
if (false) or (true) % variant #1 (original) if (true) or (false) % variant #2 if (true) or (10< 9.9) % variant #3 if true or 10< 9.9 % variant #4 if 10> 9.9 or 10< 9.9 % variant #5
Variant #1: if (false) or (true)
The first thing to note is that
or is a function and not an operator, unlike some other programming languages. Since this function immediately follows a condition (
true), it is not considered a condition by its own, and is not parsed as a part of the “if” expression.
In other words, as Roger Watt correctly stated, line #3 is actually composed of two separate expressions:
if (false) and
or(true). The code snippet can be represented in a more readable format as follows, where the executed lines are highlighted:
if (false) or (true) disp('Yaba'); else disp('Daba'); end
Since the condition (
false) is never true, the “if” branch of the condition is never executed; only the “else” branch is executed, displaying ‘Daba’ in the Matlab console. There is no parsing (syntactic) error so the code can run, and no run-time error so the “catch” block is never executed.
Also note that despite the misleading appearance of line #3 in the original code snippet, the condition only contains a single condition (
false) and therefore neither short-circuit evaluation nor eager evaluation are relevant (they only come into play in expressions that contain 2+ conditions).
As Rik Wisselink speculated and Michelle Hirsch later confirmed, Matlab supports placing an expression immediately following an “if” statement, on the same line, without needing to separate the statements with a new line or even a comma (although this is suggested by the Editor’s Mlint/Code-Analyzer). As Michelle mentioned, this is mainly to support backward-compatibility with old Matlab code, and is a discouraged programming practice. Over the years Matlab has made a gradual shift from being a very weakly-typed and loose-format language to a more strongly-typed one having stricter syntax. So I would not be surprised if one day in the future Matlab would prevent such same-line conditional statements, and force a new line or comma separator between the condition statement and the conditional branch statement.
Note that the “if” conditional branch never executes, and in fact it is optimized away by the interpreter. Therefore, it does not matter that the “or” function call would have errored, since it is never evaluated.
Variant #2: if (true) or (false)
In this variant, the “if” condition is always true, causing the top conditional branch to execute. This starts with a call to
or(false), which throws a run-time error because the or() function expects 2 input arguments and only one is supplied (as Chris Luengo was the first to note). Therefore, execution jumps to the “catch” block and ‘Doo!’ is displayed in the Matlab console.
In a more verbose manner, this is the code (executed lines highlighted):
function test try if (true) or (false) disp('Yaba'); else disp('Daba'); end catch disp('Doo!'); end end
Variant #3: if (true) or (10< 9.9)
This is exactly the same as variant #2, since the condition
10< 9.9 is the same as
false. The parentheses around the condition ensure that it is treated as a single logical expression (that evaluates to
false) rather than being treated as 2 separate arguments. Since the or() function expects 2 input args, a run-time error will be thrown, resulting in a display of ‘Doo!’ in the Matlab console.
As Will correctly noted, this variant is simply a red herring whose aim was to lead up to the following variant:
Variant #4: if true or 10< 9.9
At first glance, this variant looks exactly the same as variant #3, because parentheses around conditions are not mandatory in Matlab. In fact,
if a || b is equivalent to (and in many cases more readable/maintainable than)
if (a) || (b). However, remember that “or” is not a logical operator but rather a function call (see variant #1 above). For this reason, the
if true or 10< 9.9 statement is equivalent to the following:
if true or 10< 9.9 ...
Now, you might think that this will cause a run-time error just as before (variant #2), but take a closer look at the input to the or() function call: there are no parentheses and so the Matlab interpreter parses the rest of the line as space-separated command-line inputs to the or() function, which are parsed as strings. Therefore, the statement is in fact interpreted as follows:
if true or('10<', '9.9') ...
This is a valid “or” statement that causes no run-time error, since the function receives 2 input arguments that happen to be 3-by-1 character arrays. 3 element-wise or are performed (
'1'||'9' and so-on), based on the inputs’ ASCII codes. So, the code is basically the same as:
if true or([49,48,60], [57,46,57]) % =ASCII values of '10<','9.9' disp('Yaba');
Which results in the following output in the Matlab console:
ans = 1×3 logical array 1 1 1 Yaba
As Will noted, this variant was cunningly crafted so that the 2 input args to “or” would each have exactly the same number of chars, otherwise a run-time error would occur (“Matrix dimensions must agree”, except for the edge case where one of the operands only has a single element). As Marshall noted, Matlab syntax highlighting (in the Matlab console or editor) can aid us understand the parsing, by highlighting the or() inputs in purple color, indicating strings.
Variant #5: if 10> 9.9 or 10< 9.9
This is another variant whose main aim is confusing the readers (sorry about that; well, not really…). This variant is exactly the same as variant #4, because (as noted above) Matlab conditions do not need to be enclosed by parentheses. But whereas
10> 9.9 is a single scalar condition (that evaluates to
10< 9.9 are in fact 2 separate 3-character string arguments to the “or” function. The end result is exactly the same as in variant #4.
I hope you enjoyed this little puzzle. Back to serious business in the next post!
I will be travelling in the US (Boston, New York, Baltimore) in May/June 2019. Please let me know (altmany at gmail) if you would like to schedule a meeting or onsite visit for consulting/training, or perhaps just to explore the possibility of my professional assistance to your Matlab programming needs.
Thank you so much for this analysis.
Also, I find it somewhat horrifying.
The take away seems to be to use && / || and NOT and / or.
Thanks a bunch!