Skip to content

Booleans and logic

Lesson 3.4

Programs make decisions by asking yes/no questions. In Lua the answers are the booleans true and false.

Comparisons

A comparison gives a boolean:

Operator Means Example Result
== equal 5 == 5 true
~= not equal 5 ~= 3 true
< less than 3 < 5 true
> greater than 3 > 5 false
<= less or equal 5 <= 5 true
>= greater or equal 4 >= 5 false

“Not equal” is ~= in Lua. Many other languages use !=, which is an error in Lua.

local health = 6
print(health < 10)   --> true
print(health == 20)  --> false
print(health ~= 20)  --> true

Strings compare too. == checks that they are exactly the same, including upper and lower case. < sorts them alphabetically, by byte value, so all uppercase letters come before lowercase ones:

print("stone" == "Stone")  --> false
print("apple" < "banana")  --> true
print("Zebra" < "apple")   --> true

Values of different types are never equal: 1 == "1" is false. Comparing them with < is an error.

Truthy and falsy

Lua has a simple rule: only false and nil count as false. Everything else counts as true, including 0 and the empty string "".

Value Counts as
false, nil false
true, 0, -1, "", "false", {} true

This is different from some other languages, where 0 is false. In Lua, 0 is a normal number.

and, or, not

not flips a boolean:

print(not true)  --> false
print(not nil)   --> true
print(not 0)     --> false

and is true when both sides are true. or is true when at least one side is:

local has_pickaxe = true
local is_night = false

print(has_pickaxe and is_night)  --> false
print(has_pickaxe or is_night)   --> true
print(not is_night)              --> true

and and or return values

and and or don’t just give true or false. They give one of their two sides:

  • a or b gives a if a is truthy, otherwise b.
  • a and b gives b if a is truthy, otherwise a.
print(nil or "default")  --> default
print("Alex" or "default")  --> Alex
print(5 and 10)  --> 10
print(nil and 10)  --> nil

They also stop early. If the left side of or is already truthy, the right side never runs. This is called short-circuit evaluation.

Default values with or

This makes or the usual way to give a default:

local nickname = nil
local shown = nickname or "Player"
print(shown)  --> Player

A one-line if with and/or

condition and x or y picks x when the condition is true, and y otherwise:

local health = 4
local status = health < 5 and "low" or "ok"
print(status)  --> low

The and/or trap

This only works when x is truthy. cond and false or "fallback" always gives "fallback", and so does cond and nil or "fallback". When the value in the middle might be false or nil, use a normal if.

Order of operations

not binds tightest, then comparisons, then and, then or. So a or b and c means a or (b and c). Add brackets whenever you mix and and or. It costs nothing and saves the reader from guessing.

local is_admin, is_owner, is_banned = false, true, false
print((is_admin or is_owner) and not is_banned)  --> true

nil versus false

Both count as false, but they mean different things. nil means “no value at all”, while false is a real value meaning “no”. A setting stored as false was turned off on purpose; a setting that is nil was never set. To tell them apart, compare directly:

local pvp = false
print(pvp == nil)    --> false
print(pvp == false)  --> true

Try it

A player can enter the Nether portal when they are not in creative mode or they have permission, and their health is above 5. Write the expression for health = 8, creative = true, allowed = false, and print the result. Then use or to print "Unknown" when the variable world_name is nil.

Show a solution
local health, creative, allowed = 8, true, false

local can_enter = (not creative or allowed) and health > 5
print(can_enter)  --> false

local world_name = nil
print(world_name or "Unknown")  --> Unknown

Recap: comparisons give booleans, ~= means “not equal”, only false and nil are falsy, and x or default fills in missing values.