If/When As Expressions
In Kotlin, if
and while
seem like they are fairly similar to their equivalents in other languages. when
is a bit different but it still functions a lot like switch
in Java, etc.
Where things start to get interesting is when you realize that if
and when
not only offer branching, but that they are expressions, no different than 2 + 2
.
Ternary Operator Replacement
For example, in Java, we sometimes use the “ternary operator”:
int foo = (bar > 10 ? 10 : bar)
Here, we are setting foo
equal to bar
, unless bar
is over 10
, in which case we cap foo
at 10
. The parenthetical expression returns what appears between the ?
and the :
if the boolean expression on the left is true
, otherwise it returns what appears after the :
.
Kotlin lacks ternary support, but more than makes up for it by allowing if
to serve in the same role:
val bar = 5
val foo = if (bar > 10) 10 else bar
println(foo)
This is the same business rule as in Java, just implemented using an if
.
Our if
can have full braces-wrapped code blocks, if we need them:
val bar = 5
val foo = if (bar > 10) {
10
}
else {
bar
}
println(foo)
The value of the last statement of the block is what that block evaluates to. In this case, each of those blocks is a single statement, but if we had several statements in a block, while they are all executed, the value from the last statement is used for the result (assuming that block is used, based on the conditional expression).
when
Expressions
when
can also be used as an expression:
val i = 3
val message = when (i) {
in 3..10 -> "something"
in 1..2 -> "something else"
else -> "and now for something completely different"
}
println(message)
Here, the when
evaluates to a string, which is assigned to message
and printed.
Technically, the branches of the if
or when
do not have to evaluate to the same type. So, this runs:
val i = 3
val message = when (i) {
in 3..10 -> "something"
in 1..2 -> 5
else -> "and now for something completely different"
}
println(message)
However, you will get some compiler warnings:
warning: conditional branch result of type String is implicitly cast to Any
in 3..10 -> "something"
^
warning: conditional branch result of type Int is implicitly cast to Any
in 1..2 -> 5
^
warning: conditional branch result of type String is implicitly cast to Any
else -> "and now for something completely different"
Here, the compiler is telling you that since the branches evaluated to different types, the implied type of message
is Any
. Any
in Kotlin is roughly analogous to Object
in Java — it is the root type of the class hierarchy. Every class in Kotlin eventually extends from Any
. Any
is the only common ancestor class of Int
and String
, which is why the compiler chose that as the type for message
. However, the warning is there to hint to you that perhaps what you wrote is not what you really have in mind.
Else Required
Normally, if
and when
do not have to be “exhaustive”. Here, “exhaustive” does not mean that it makes you tired (that would be “exhausting”). Rather, “exhaustive” means that all possibilities are covered by some branch. So, this is exhaustive:
if (i>10) {
// do something
}
else {
// do something else
}
Here, no matter what the value of i
is, one of the two branches will be taken.
This, however, is not exhaustive:
if (i>10) {
// do something
}
Nor is this:
val i = 3
when {
i > 10 -> println("something")
i > 2 -> println("something else")
}
In these cases, there are values for i
for which none of the branches is valid. In that case, the if
or when
simply does not do anything.
For standalone if
and when
statements, this is fine. However, if you are going to use if
and when
as expressions, they must be exhaustive. After all, we are trying to evaluate the value of the if
or when
, and we do not have a value if there is some input for which no branch qualifies.
If you try a non-exhaustive if
or when
for an expression, such as:
val i = 3
val message = when (i) {
in 3..10 -> "something"
in 1..2 -> 5
}
println(message)
…you will get a compiler error:
error: 'when' expression must be exhaustive, add necessary 'else' branch
val message = when (i) {
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.