Kotlin: An Illustrated Guide • Chapter 3

Kotlin Conditionals: When and If

Chapter cover image

In real life, we do different things depending on the circumstances. For example, if it’s raining outside, I’ll probably grab an umbrella. If it’s sunny outside, I’ll grab my sunglasses. I do different things depending on the weather.

Similarly, we often need our code to do different things in different situations.

In this chapter, we’ll learn all about conditionals in Kotlin, which will allow us to change the way the code runs depending on circumstances!

Goldilocks and the Three Branches

You might have heard the fairy tale of Goldilocks and the Three Bears.

Papa Bear, Mama Bear, and Baby Bear lived in a quaint house nestled in the woods. One day, after preparing some porridge for breakfast, the three bears decided to go out for a leisurely stroll.

Meanwhile, a young girl named Goldilocks peeked in through the window and saw three bowls of porridge. Since she was hungry and saw nobody home, she decided to walk on inside and taste the porridge for herself.

  • First, she tried Papa Bear’s porridge, and exclaimed, “It’s too hot!”
  • Then she tried Mama Bear’s porridge, and complained, “It’s too cold!”
  • Finally, she tried Baby Bear’s porridge, and found the temperature to be perfect. “It’s just right!” she said, and ate the entire bowl.

Let’s map out Goldilocks’ reaction to the three different bowls of porridge into a simple table:

Temperature Goldilocks’ Reaction
Greater than 55°C “It’s too hot!”
Less than 40°C “It’s too cold!”
Anything else “It’s just right!”

Goldilocks responds differently depending on the temperature of the porridge.

  1. When it’s above 55°C, she says, “It’s too hot!”
  2. When it’s below 40°C, she complains, “It’s too cold!”
  3. But anything in between, and she’ll say, “It’s just right!”

We can write Kotlin code that will tell us which of these three things Goldilocks will say, based on the temperature of the porridge. In programming terms, the three different cases above - that is, the three different rows of the table - are called branches. If it helps, you can visualize the branches like you’d see on a tree:

A tree with one branch for too hot, one branch for too cold, and one branch for just right.

So far, when we’ve run the code that we’ve written, every line of code has run. But now, we’re going to start writing code instead where only one of the branches will run each time. While your code is running, the path that is run - including the particular branch that it takes - is referred to as the execution path.

Here you can see the three possible execution paths that our Kotlin code could take, depending on the temperature:

The same tree shown three times. Each one has an arrow running from the trunk to one branch.

Code constructs that choose between different branches (e.g., different responses from Goldilocks) based on some condition (e.g., the temperature) are called conditionals.

So how can we write Kotlin code that tells us how Goldilocks will respond to each bowl of porridge? Kotlin has a couple of conditionals that we can use. Let’s check ‘em out!

Introduction to when in Kotlin

Let’s look at that table again.

Temperature Goldilocks’ Reaction
Greater than 55°C “It’s too hot!”
Less than 40°C “It’s too cold!”
Anything else “It’s just right!”

A table like this is easy to read and understand. We can just scan down the left-hand column, and when we find the temperature of the porridge that Goldilocks is eating, we look to the right to see how she will respond.

Kotlin gives us a powerful conditional called when, which enables us to basically write that same table in our code. Here’s how it looks.

val temperature = 48

val reaction = when {
	temperature > 55 -> "It's too hot!"
	temperature < 40 -> "It's too cold!"
	else             -> "It's just right!"
}

Just to show how similar this is to our table, let’s add a little spacing and put the table next to it.

A when expression in Kotlin, with the same table next to it. The same code is found in Listing 3.1 above.

As you can see, this looks almost identical to our table above! Each line between the opening brace { and the closing brace } is just a row from our table.

The reaction variable will be assigned a different value depending on the value of the temperature variable:

  • When the temperature is greater than 55, then reaction will be assigned "It's too hot!"
  • When the temperature is less than 40, then reaction will be assigned "It's too cold!"
  • Otherwise, reaction will be assigned "It's just right!"

To really understand when, let’s look at the different parts:

The different parts of a 'when' expression, explained below.
  1. First, there’s when. This is a keyword that tells Kotlin that you want to do something different depending on the circumstances. Note that when is an expression, so it is evaluated and can be assigned to a variable. In this case, it will evaluate to a string, which will be assigned to the reaction variable.
  2. Next, there are temperature > 55 and temperature < 40. These are called conditions. Conditions are expressions that evaluate to a Boolean.

    temperature > 55 just asks the question, “is the temperature variable is greater than 55?” If is indeed greater than 55, then it evaluates to true. Otherwise it evaluates to false. When you need to compare numbers in Kotlin, you can use things like the greater-than sign > or the less-than sign <. The fancy term for these is comparison operators. See the chart below for more information.

  3. When the condition evaluates to true, then the when expression will evaluate to the value on the right side of the arrow ->.
  4. At the bottom, we have else, which is a catch-all branch that’s used in case none of the conditions above it match.

The when expression is quite helpful, and you’ll probably use it often. It also has some interesting characteristics. Let’s look at a few of them now.

The First True Condition Wins

Goldilocks just found some more porridge in the freezer, so let’s add another case for extremely cold temperatures:

val temperature = -5

val reaction = when {
	temperature > 55 -> "It's too hot!"
	temperature < 40 -> "It's too cold!"
	temperature < 0  -> "It's frigid!"
	else             -> "It's just right!"
}

In this code listing, because the temperature variable is set to -5, you might expect reaction to be set to "It's frigid!", but actually, it would be set to "It's too cold!".

Why is that?

Because Kotlin works through the when cases from top to bottom.

  1. First, temperature > 55 evaluates to false, because -5 is not greater than 55.
  2. Then, temperature < 40 evaluates to true, because -5 is indeed less than 40.

At this point, Kotlin uses "It's too cold!", because it found a matching condition. So, the third case - temperature < 0 - is never evaluated.

In other words, the first condition that evaluates to true will win.

It’s easy to make sure that "It's frigid" is used when the temperature is below zero. Just put that case before the condition where the temperature is below 40 degrees, like this:

val temperature = -5

val reaction = when {
	temperature > 55 -> "It's too hot!"
	temperature < 0  -> "It's frigid!"
	temperature < 40 -> "It's too cold!"
	else             -> "It's just right!"
}

Now, when you run this code, the temperature < 0 case will run before temperature < 40, so reaction will be "It's frigid!".

Exact Matches

Sometimes, instead of checking for a range of values (e.g., “anything greater than 55”, or “anything less than 40”) we only need to check for an exact match.

After the Three Bears discovered how much Goldilocks liked their porridge, they decided to write a cookbook that includes all of their family recipes. They opened an online store and began selling their books. Since the book is so popular, they wanted to give discounts to people who buy multiple copies of it.

Here’s the discount schedule:

Quantity Ordered Price Per Book
1 book $19.99 each
2 books $18.99 each
3 books $16.99 each
4 books $16.99 each
5 or more books $14.99 each

We could write the when statement like this:

val quantity = 3

val pricePerBook = when {
	quantity == 1 -> 19.99
	quantity == 2 -> 18.99
	quantity == 3 -> 16.99
	quantity == 4 -> 16.99
	else          -> 14.99
}

However, Kotlin lets you shorten this up even more, by letting you specify a subject. Here’s how that looks:

val quantity = 3

val pricePerBook = when (quantity) {
	1    -> 19.99
	2    -> 18.99
	3    -> 16.99
	4    -> 16.99
	else -> 14.99
}

In this example, quantity is called the subject of the when expression. The subject can be any expression1, but here we just used the variable quantity. Because we used quantity as the subject, we no longer had to put quantity == in each condition!

There’s one more shortcut that Kotlin gives us, allowing us to make this even more concise. Since the price-per-book for 3 books is the same as that for 4 books, we can put those conditions on the same line, separated by a comma, like this:

val quantity = 3

val pricePerBook = when (quantity) {
	1    -> 19.99
	2    -> 18.99
	3, 4 -> 16.99
	else -> 14.99
}

Every Condition Must Be Accounted For

A when expression in Kotlin must include conditions for all possible values. For this reason, we say that a when expression must be exhaustive. This is also the reason that you usually need to include an else condition at the bottom.

Sometimes you can be exhaustive even without an else condition. For example, consider a Boolean expression. As you recall, Booleans have only two possible values - true and false.

Kotlin knows that a Boolean value can only ever be true or false. So, as long as we have a branch for both of those cases, then we won’t need an else case.

val isLightbulbOn = true

val reaction = when (isLightbulbOn) {
	true  -> "It's bright"
	false -> "I can't see"
}

This isn’t the only occasion when you can omit the else condition. We’ll see this again when we learn about enum classes and sealed classes.

The when expression is powerful, and as a Kotlin developer, you’ll use it a lot! But it can be a bit heavy-handed for simple Boolean checks like for our lightbulb above. For these cases, Kotlin gives us a second kind of conditional.

if Expressions

We can make our lightbulb example even more concise by using an if expression instead of a when expression. if expressions are kind of like when expressions, but they have a single condition, and two cases - one for true and one for false.

Here’s how it looks:

val reaction = if (isLightbulbOn) "It's bright" else "I can't see"

And here are the different pieces:

An 'if' expression in Kotlin.

if is a keyword, like when. isLightbulbOn is the condition that is evaluated.

  • If it evaluates to true, then reaction will be assigned "It's bright"
  • If it evaluates to false, then reaction will be assigned "I can't see"

If you like, you may format this so that the branches are on different lines. For example:

val reaction =
	if (isLightbulbOn)
		"It's bright"
	else
		"I can't see"

You can also use braces { and } around the branches. Doing so allows you to add statements to the branches, like this:

var isLightbulbOn = true

val reaction =
	if (isLightbulbOn) {
		isLightbulbOn = false
		"I just turned the light off."
	} else {
		isLightbulbOn = true
		"I just turned the light on."
	}

Generally, as a Kotlin programmer, if you’ve got a single condition to check, you use an if expression. If you’ve got multiple conditions to check, you use a when expression.

It’s possible to use if for more than one condition. For example, remember our price-per-book lookup in Listing 3.5? We could rewrite it into an if expression, like this:

val pricePerBook =
	if (quantity == 1)
		19.99
	else if (quantity == 2)
		18.99
	else if (quantity == 3)
		16.99
	else if (quantity == 4)
		16.99
	else
		14.99

If you find yourself doing this, stop!

Stop sign

Use a when expression instead!

when and if as Statements

So far, we’ve used the when and if conditionals as expressions, but you can also use them as statements. Here’s an example of using an if statement in Kotlin:

var wattage = 0
var lightbulbIsOn = true

if (lightbulbIsOn) {
    wattage = wattage + 12
}

A few interesting things to note here:

  • Unlike conditional expressions, conditional statements do not require an else branch. In the example above, if lightbulbIsOn is false, then the single branch that’s there (wattage = wattage + 12) will simply never run.
  • We did not assign this if to a variable, because as you recall, you cannot assign a statement to a variable.

Summary

In just three chapters, you’ve already learned a lot about Kotlin! You know about variables, types, expressions, statements, and functions. And in this chapter, you learned all about conditionals, including:

  • What branches and conditions are.
  • How the when expression can be used to pick a different value in different situations.
  • How an if expression can be a good fit for cases where you’ve only got two branches.
  • How you can use when and if as statements.

In this course, we’ve used a variety of types, such as integers, strings, and Booleans. In the next chapter, we’ll start putting variables and functions together to create our very own types, using classes and objects. These concepts will open many exciting possibilities for us to start writing more advanced programs. See you then!

Thanks to David Blanc, Raheel Naz, and Mohit for reviewing this chapter.


  1. As of Kotlin 1.3, you can also capture the subject into a variable. [return]

Share this article: