How Lua logical operators work

Today a intern at Kidoteca, asked me a interesting question while learning Lua:

“Why print(4 and 5)  prints the number 5?”

This took me a little by surprise, although I use some Lua logical operators hackery, I did not really remember how they worked… So I went to read a bit the specifications, and found the answer to be interesting enough to warrant this article.

Lua has three logical operators, they are and , or  and not .

Conversion to boolean

They follow the same rules as the control structures to consider what is true , and what is false . Lua considers everything true , unless it is the boolean value false , or nil .

Logical operators behaviour

not is simple enough, it converts whatever is to the right of it to a boolean value and negate it.

and returns the first argument if it is false, otherwise the second. We will explore the reason for that, and how it can be exploited later.

or do the exact opposite of and , it returns the second argument if the first one is false.

Short-circuit evaluation

Also, both or  and and  stop evaluations as soon they can, meaning that in case of an and , it does not evaluate the second argument if the first is false, and or  does not evaluate the second if the first is true.

The last particular property is useful for many things, in my opinion the two most important are performance savings (ie: stop checking stuff if you already know the result) and checking something about a data inside a table.

For example, if you want to check if myTable.myData  is loaded, you can just check if myData  exists, but what if myTable  does not exist? You get a nasty runtime error! The solution is use the and  operator and also check for the existence of myTable .

OR and AND (lack of) type conversion

People coming from other languages, like C for example, might be confused: “Why Lua logical operators return an operand, instead of returning true  or false ?”. This is because there is no need to do otherwise. Lets evaluate ourselves the following example.

The first part is decide evaluation ordering, in Lua the operator or  has the lowest precedence of all, being the last thing evaluated, and  is just a bit higher, and not  is one of the highest, thus not  is evaluated first, if we edit our code and put the result in place it becomes:

not print  became false , because print  was a function, and it became true , and the not  negated it, becoming false . Now the left-most and  operator is evaluated.

The operands were 5 and false, since 5 is true (because everything that is not false , or nil , is true), and the and  operator in that case returns the second argument, it returned false . Now we will evaluate the second and .

This time we had as operators "string"  and false , since any string is true, and  returned false  (that was created by the not print ). Now we evaluate the or .

The or  returns the second argument when the first argument is false, since the second argument was false too, the result is false, so the program now will print "false" .

And in case of true? For example 1 and 5 . In this case, and  will return 5 to the if (because 1 is true), and when the if clause evaluates the 5, it will convert it to true . Note this is two evaluation steps, different from how C++ works for example, where the and  operator will check if both sides are true and return true  or false .

Logical operator hacks

Logical operators because the way they work in Lua allow some interesting constructions, the most popular one is to have default values.

Like we said before, or  returns the second argument if the first is false  or nil , this mean that you cannot use this constructions if you want to keep false  (or nil ) as a valid value.

The other use is imitate C ternary (?:) operator, x = a ? b : c;  results into b  getting assigned into x  if a  is true, and c  getting assigned into x  if a  is false.

It works by first evaluating the and , if the first operand is false, and will return a false, that in turn will force the or  to return the second operand. If the first operand is true, and  will return the second operand, if the returned operand is not false, or  will return it, this also means that the second operand must not be false  or nil , otherwise this construction will fail.

References

Lua Manual

Programming in Lua Chapter 3