17. Boolean logic in depth

Chapter 16 used and, or, and not to join conditions. They do more than that: knowing what they really return unlocks tricks that Lua and Roblox code lean on constantly. This chapter goes deeper into truth.

Truthy and falsy, again

Recall the rule from Chapter 16: in a condition, only false and nil count as false. Everything else is true — including 0, the empty string "", and 0.0. Lua calls those two falsy and the rest truthy.

if 0 then print("zero is truthy") end       -- prints
if "" then print("empty is truthy") end     -- prints
if nil then print("never") end              -- does not print

This surprises people from other languages, where 0 is often false. Not in Lua. Keep it in mind whenever you test a value directly.

and and or hand back a value

Here is what beginners rarely get told: and and or do not return true or false. They return one of their two sides, unchanged.

  • a and b → if a is falsy, it returns a; otherwise it returns b.
  • a or b → if a is truthy, it returns a; otherwise it returns b.
print(5 and 10)          -- 10   (5 is truthy, so the second value)
print(nil and 10)        -- nil  (first is falsy, returned as-is)
print(false or "hi")     -- hi   (first falsy, so the second)
print("yes" or "no")     -- yes  (first truthy, returned at once)

Used in an if, this behaves like plain true/false logic — but the returned value is what makes the tricks below possible.

The default-value trick: x or default

Because or returns its first truthy side, you can supply a fallback for a value that might be nil. Picture a name that may be empty:

local typed_name = nil                 -- nothing was entered
local name = typed_name or "stranger"
print("Hello, " .. name)               -- Hello, stranger

If typed_name had held a real value, name would keep it instead. This x or default line is the standard Lua way to fall back to a default — you will see it everywhere a value might be missing.

Open exercises/17/01-default.lua. chosen is set to nil. Use chosen or "rock" to fall back to "rock", then print it. Set chosen to a real word and run again.

Short-circuit: the second side is skipped

and and or are lazy. They stop as soon as the answer is certain:

  • a and b — if a is falsy, b is never even looked at.
  • a or b — if a is truthy, b is never looked at.

This lets the first test guard the second, which runs only after the first has passed:

local total = 90
local count = 0
-- the average is only worth working out when count is not zero,
-- so the count check guards the division
if count > 0 and total / count > 20 then
    print("high average")
else
    print("no average to show")
end

Because count > 0 is false, Lua never evaluates total / count — it short-circuits straight to the else. The pattern if x > 0 and something-using-x shows up constantly.

not flips truthiness

not turns any value into a real boolean — true if it was falsy, false if it was truthy:

print(not nil)      -- true
print(not 0)        -- false   (0 is truthy, so "not 0" is false)
print(not false)    -- true

It is handy for asking "is this missing?":

local key = nil
if not key then
    print("You need a key.")
end

Homework

Homework files are in exercises/17/homework/.

Problem 1 — Default colour

Open exercises/17/homework/01-default-colour.lua. fav holds a colour or nil. Using or, set colour to fav, or to "blue" when fav is nil, then print Your colour is <colour>. Run it once with fav = nil and once with a real colour.

Problem 2 — Truthy table

Open exercises/17/homework/02-truthy.lua. For each of these values, print the value and whether it is truthy, using not not value to turn it into a real boolean: 0, "", nil, false, "hi". (Two nots flip falsy→false→true and truthy→true→... try it and see.)

Problem 3 — Guarded division

Open exercises/17/homework/03-guarded.lua. Two numbers: total and count (which might be 0). Using and, print the average total / count only when count is greater than 0; otherwise print no data. Test it with count set to 0 and to a real number.

Challenge — First value that exists

Open exercises/17/homework/04-first-value.lua. Three variables a, b, c each hold a string or nil. In one line using or, print the first one with a value, or none if all three are nil. Try different combinations of values and nil.

Stuck or finished? Open the homework solutions page.