CodeRigor

LESSON

Make decisions with if, elseif and else

Compare values, choose between blocks with if, elseif and else, and combine conditions with and, or and not.

Every program so far ran all of its statements, top to bottom, every time. Real programs respond to their input: they do one thing for some answers and something else for others. For that a program needs to ask a yes-or-no question and choose what to run.

Conditions are true or false

A comparison asks a question about two values. Its answer is one of two special values, true or false. These two values are called booleans.

Lua
print(3 < 5)
print(3 > 5)
print(4 == 4)
print(4 ~= 4)

This prints true, false, true and false.

There are six comparison signs:

Sign Meaning
== is equal to
~= is not equal to
< is less than
> is greater than
<= is less than or equal to
>= is greater than or equal to

Take care with the first one. A single = assigns a value to a variable. A double == asks whether two values are equal. The "not equal" sign is a tilde followed by an equals sign: ~=.

An expression that works out to true or false is called a condition.

if runs a block only when its condition is true

Lua
local temperature = 30

if temperature > 25 then
    print("It is warm.")
    print("Open a window.")
end

print("Done.")

This prints It is warm., Open a window. and Done.. Change the 30 to 20 and run it again: now only Done. is printed.

An if statement has four parts: the word if, a condition, the word then, and, some lines later, the word end. The statements between then and end are called a block. They run when the condition is true, and are skipped when it is false. Either way, the program continues with whatever comes after end.

The statements in the block are moved to the right by four spaces. This is called indentation. Lua does not need it, but people do: it shows at a glance which statements belong to the if. Indent every block.

else gives the other path

Add else to say what should happen when the condition is false:

Lua
local age = 15

if age >= 18 then
    print("You may vote.")
else
    print("You may not vote yet.")
end

This prints You may not vote yet.. Exactly one of the two blocks runs, never both and never neither. There is still only one end, after the last block.

if and else: two paths, one is taken
start / 4 ⇄ code
The condition is worked out once. True leads to the first block, false to the block after else. Both paths meet again after end.
if and else: two paths, one is taken
The condition is worked out once. True leads to the first block, false to the block after else. Both paths meet again after end.

elseif chooses between several paths

When there are more than two possibilities, put elseif (one word) with a further condition between the if and the else:

Lua
local score = 72

if score >= 90 then
    print("Grade A")
elseif score >= 70 then
    print("Grade B")
elseif score >= 50 then
    print("Grade C")
else
    print("Not passed")
end

This prints Grade B.

Lua checks the conditions from the top and runs the block of the first one that is true. Then it jumps to the end; the remaining conditions are not even looked at. A score of 72 is also at least 50, but Grade C is not printed, because the chain stopped at the first match. The else block runs only when every condition was false.

An if / elseif / else chain stops at the first true condition
start / 4 ⇄ code
Conditions are tested in order. The first true one runs its block and the chain is over. else catches everything that is left.
An if / elseif / else chain stops at the first true condition
Conditions are tested in order. The first true one runs its block and the chain is over. else catches everything that is left.

Because the first match wins, order matters. Put the most demanding condition first. If the chain above began with score >= 50, every passing score would be Grade C.

Write elseif as one word. else if with a space starts a second, separate if inside the else block, and that one needs an end of its own.

Decisions on input

Conditions become useful when the values come from the user. Remember to convert the answer to a number first.

Lua
io.write("How many items? ")
local items = tonumber(io.read("l"))

if items == 0 then
    print("Your basket is empty.")
elseif items == 1 then
    print("1 item in your basket.")
else
    print(items .. " items in your basket.")
end

With the answer 3 the session is:

Text
How many items? 3
3 items in your basket.

Paste it into the Lua playground and try 0, 1 and 3 in the Standard input box.

Strings can be compared with == and ~= too: answer == "yes" is true only when the text is exactly yes, with the same capital and small letters.

Combining conditions

Three words build bigger conditions out of smaller ones:

  • a and b is true only when both are true.
  • a or b is true when at least one is true.
  • not a turns true into false and false into true.
Lua
local age = 10
local height = 130

print(age >= 8 and height >= 120)
print(age >= 12 or height >= 150)
print(not (age >= 8))

This prints true, false and false. In the first line both parts are true. In the second, neither is. In the third, age >= 8 is true, and not reverses it.

In an if, a combined condition reads almost like English:

Lua
local day = "Sunday"
local raining = false

if day == "Sunday" and not raining then
    print("Go for a walk.")
else
    print("Stay in.")
end

This prints Go for a walk.

A number between two limits needs two comparisons joined by and: age >= 13 and age <= 19. Each side of and must be a complete comparison.

Three errors you will meet

One equals sign in a condition.

Lua
local age = 18
if age = 18 then
    print("Happy birthday!")
end
Text
solution.lua:2: 'then' expected near '='

Lua read if age and was ready for the word then, but found a single =, which cannot appear in a condition. The fix is ==. Whenever a message says 'then' expected, look at the condition on that line: the usual causes are = in place of ==, or a forgotten then.

A missing end.

Lua
local temperature = 30
if temperature > 25 then
    print("It is warm.")
print("Done.")
Text
solution.lua:5: 'end' expected (to close 'if' at line 2) near <eof>

<eof> stands for "end of file". Lua reached the end of the program while still waiting for an end. As with the missing bracket in the last lesson, the useful part is in the brackets: the if that was never closed is on line 2. Indentation makes this mistake easy to spot: the last line is not indented, so an end belongs above it.

Comparing text with a number. This program forgot tonumber:

Lua
local typed = "15"     -- stands in for what the user typed
if typed < 18 then
    print("Child ticket")
end
Text
/usr/bin/lua: solution.lua:2: attempt to compare string with number
stack traceback:
	solution.lua:2: in main chunk
	[C]: in ?

Line 2 asks whether a piece of text is less than a number, and Lua refuses to guess what that means. Convert the input when you read it: local age = tonumber(io.read("l")).

A related trap gives no error at all: "15" == 15 is false, because a string and a number are never equal. Unconverted input makes an == test quietly fail.

What you can do now

You can compare values, write if / elseif / else chains that run exactly one block, combine conditions with and, or and not, and recognise the three commonest error messages. In the exercises you will trace which branch runs and then write a program that gives one of three answers.

Next: repeat steps with for and while.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Starts at 'Conditionals' (10:53), about four and a half minutes, typed out quickly. Stop at 'Ternary Operator' (15:20), a shortcut this unit does not use.