Using And & Or for Control Flow

In the Logical Operators section we learned how the and and or operators can be used to implement logic in conditional expressions, such as those used to control flow in the if-then statements we discussed in the previous section.

It turns out that the and and or operators are implemented similarly to if-then statements, which allows them to provide simple and convenient control flow in some common situations.

Default Value

There are many situations where we want to assign a value to a variable if one exists, then fall back to a default value if needed. This can be implemented as a simple if-then statement like this:

local function might_return_nil()
return nil
end

local x = might_return_nil()

if x == nil then
x = "default"
end

print(x) -- default

There is nothing wrong with this code, but in some cases the or operator can be used to create equivalent functionality that is more compact and easier to read.

Recall that the or operator returns the first truthy value it encounters, or the last falsy value when all values are falsy. This provides a convenient method of implementing the previous example in a somewhat more concise manner:

local function might_return_nil()
return nil
end

local x = might_return_nil() or "default"

print(x) -- default

One of the nice aspects about this is that the code reads like common english: assign either the first value or the second value.

Priority

There are also some situations where a variable could be assigned one of several values, depending upon some application-dependent prioritization. This could be implemented using an if-then-else statement as follows:

local function lower_priority()
return "lower"
end

local function medium_priority()
return "medium"
end

local function high_priority()
return "high"
end

local x

if high_priority() then
x = high_priority()
elseif medium_priority() then
x = medium_priority()
else
x = lower_priority()
end

print(x) -- high

Suppose that each of the functions returns either a truthy value or a falsy value. In this example we check each prioritization, from highest to lowest, to determine what value should be assigned to x.

Recall that the and operator returns the first non-truthy value, or the last truthy value if all values are truthy. This behavior can be leveraged to provide a more compact solution:

local function lower_priority()
return "lower"
end

local function medium_priority()
return "medium"
end

local function high_priority()
return "high"
end

local x = lower_priority() and medium_priority() and high_priority()

print(x) -- high

Although this is much more compact than the previous example, the downside is that it doesn't read like common english, which can make it difficult to read. Still, once this pattern is understood it can be a simple, concise means of applying prioritization.