Pocket Studio Academy
HomePart 11.5

if / else — making decisions

Free lesson9 min read·4 questions

Until now your programs have run straight down the page. if is where they start to choose — checking a condition and taking one path or the other. It is also, in Kotlin, something that can hand back a value.

A program that always does the same thing is a list

Everything you have written so far runs top to bottom, every time, no matter what. That is useful for a shopping list and useless for an app.

Real apps decide. If the password is right, let them in. If the score beats the record, show the fireworks. If there are no notes yet, show "nothing here yet" instead of an empty white screen.

One keyword does all of it.

kotlin
1if (score > 100) {
2  println("New record!")
3}

Read it as an English sentence, because it almost is one: if this is true, then do the things in the brackets. If it is not true, skip them entirely.

Think of it like this

Picture a path through a wood that splits in two, with a sign at the fork:

Wet weather? Go left. Otherwise go right.

Three things are worth noticing about that sign, and all three are true of in code.

First, the question has exactly two answers. It is wet or it is not. There is no "sort of".

Second, you take one path or the other — never both, never neither.

Third, the paths join up again further on. Whichever way you went, you carry on with the rest of the walk afterwards.

Asking a question

The bit in the round brackets is called the , and it must produce a true or false. Nothing else will do. You build one with a :

OperatorAsks
>Is the left bigger?
<Is the left smaller?
>=Bigger than or equal to?
<=Smaller than or equal to?
==Are they the same?
!=Are they different?

The one that catches everybody is ==. One equals sign means "put this value into that name". Two means "are these the same?". Kotlin will not let you confuse them — writing if (x = 5) gives Assignments are not expressions, which is Kotlin saying "that line stores something, it does not ask anything".

The other path

if on its own does something or nothing. Add and you get a genuine fork:

kotlin
1if (age >= 18) {
2  println("Come in")
3} else {
4  println("Not tonight")
5}

Exactly one of those two lines runs. Never both.

For more than two paths, chain with else if:

kotlin
1if (score >= 90) {
2  println("Gold")
3} else if (score >= 60) {
4  println("Silver")
5} else {
6  println("Try again")
7}

Kotlin checks the conditions in order and stops at the first one that is true. That matters more than it looks. With a score of 95 the first branch wins and the second is never even looked at — which is exactly why the tests are written biggest-first. Swap them round and every score above 60 would come out Silver.

Combining questions

Sometimes one test is not enough. Three join them up:

  • && means and — true only when both sides are true.
  • || means or — true when at least one side is true.
  • ! means not — it flips true to false and false to true.
kotlin
1val age = 15
2if (age >= 13 && age <= 19) {
3  println("Teenager")
4}
5if (age < 13 || age > 19) {
6  println("Not a teenager")
7}

Two tips that save real time. First, Kotlin is lazy on purpose: in a && b it does not even look at b if a was false, because the answer cannot change. Second, when a condition grows past about three parts, give it a name:

kotlin
1val isTeen = age >= 13 && age <= 19
2if (isTeen) {
3  println("Teenager")
4}

That is a val holding a Boolean, and it reads better than the thing it replaced.

The Kotlin bit: if hands back a value

In most languages if just does things. In Kotlin it is an — it produces a value, which means you can put it on the right of an =:

kotlin
1val a = 12
2val b = 30
3val biggest = if (a > b) a else b
4println(biggest)

No curly brackets needed for one-liners. biggest is 30.

There is one rule: an if used this way must have an else. Kotlin has to end up with a value whatever happens, and without an else there is a path that produces nothing. Leave it out and you get 'if' must have both main and 'else' branches if used as an expression.

Reading a decision line by line

Try it in Pocket Studio
  1. Open Pocket Studio, tap Projects, open KotlinLab, then open Lab.kt.
  2. Clear the inside of main and type in the eleven-line program from the walkthrough above.
  3. Tap Run. You should see Silver, then Result: pass.
  4. Change val score = 72 to val score = 95 and run again. Now it says Gold.
  5. Try val score = 12. You get Try again and Result: fail.
  6. Try exactly val score = 60. It says Silver, because >= includes the number itself. Change that test to score > 60 and run again — now 60 falls through to Try again. The difference between > and >= is a whole grade boundary.
  7. Break it deliberately: delete the else from line 10 and press Run. Read the error, then put it back.
Error Doctor5 common errors
e: Type mismatch: inferred type is Int but Boolean was expected
MeansThe condition does not ask a question. You wrote something like if (score) where a number sits alone in the brackets.
FixCompare it against something: if (score > 0). Unlike some other languages, Kotlin never treats a number as a stand-in for true or false — and that strictness stops a lot of guessing.
e: Assignments are not expressions, and only expressions are allowed in this context
MeansYou used one = inside the condition. That line stores a value; it does not ask anything.
FixUse two: if (name == "Ada"). One = puts a value in, two == compares.
e: 'if' must have both main and 'else' branches if used as an expression
MeansAn if on the right of an = has no else, so there is a path where nothing at all would be produced.
FixAdd an else branch. Every route through the expression has to end up with a value.
e: Expecting '('
MeansThe condition is missing its round brackets — if score > 5 { rather than if (score > 5) {.
FixWrap the condition in round brackets. Kotlin always requires them after if and while.
e: Unresolved reference: isTeen
MeansYou declared a name inside a { } block and then used it outside. Names live and die with the block that declared them.
FixMove the declaration outside the block, above the if, so it is in for both branches.
Recap
  • runs a only when its is true; covers the other case.
  • The condition must be a . Build one with >, <, >=, <=, == or != — and remember == compares while = assigns.
  • else if chains are checked in order and stop at the first match, so write the narrowest test first.
  • Join conditions with && (both), || (either) and ! (not). Name long conditions.
  • In Kotlin if is an : val max = if (a > b) a else b. Used that way, the else is compulsory.
  • Next: when you are testing the same value against five different possibilities, an else if chain gets ugly. when is the tidy answer.