The Programmers Guide To Kotlin - If and When
Written by Mike James   
Monday, 05 July 2021
Article Index
The Programmers Guide To Kotlin - If and When
The When
IF V When

The When

One common way to simplify nested if statements is to use what in other language is called a select. In Kotlin a multi-way conditional is called a when expression. A when matches its argument against each of the branches and executes the one that matches. If none match then an else clause can provide a default, for example:

when(a){
"s"->println("stop received")
"r"->println("run received")
}

In this case a is a String and its contents are matched against the examples. Note: a doesn't have to be declared as a string, but it has to be initialized to a string. You can use any type for which equality makes sense – String, Double, Int and so on. Of course, you aren't restricted to a single instruction following the -> as you can use a compound statement in curly brackets.

Notice that there is no "fall through" typical of other languages. That is, if a clause is executed then control passes to the instruction following the end of the when. There is no need for a break or any other exit instruction within each clause. The clauses are tested sequentially from the top and the first one to match is executed and this ends the when.

If none of the clauses match then nothing happens and execution passes to the next instruction beyond the when. If you want a default clause then you can use an else:

 when(a){
1->println("stop received")
2->println("run received")
else -> println("unrecognized")
}

This is the most basic when statement and if this was all it was capable of it would be useful but restricted to selecting actions based on a set of fixed discrete values. Fortunately, the when statement has some more advanced aspects.

You can, for example, combine selection values using a comma:

when(a){
1,3->println("stop received")
2,4->println("run received")
else -> println("unrecognized")
}

If any of the values matches the argument then the clause is executed and the when exited. Notice that these values are tested right to left and this provides a way of writing a logical OR.

You can also use an arbitrary expression to match against. For example:

when(a){
2*2->println("stop received")
c*b+5->println("run received")
else -> println("unrecognized")
}

You can use constants and variables and the expression is evaluated at the time the when is executed.

As a slight extension, the expression can also be a range:

For example:

var a=8
when(a){
        in 1..10 ->println("1 to 10")
        !in 1..5 ->println("not 1 to 10")
       }

Here in 1..10 is true as the variable a is in 1 to 10 and !in 1..5 is true if a is not in 1 to 5. You might think, at first, that the second message in the println is a typo and should be "not in 1 to 5", but it illustrates the scope for getting things wrong when writing even simple conditions. The first clause is executed if a is in the range 1 to 10 and then the when is exited. This means that the second clause is only tested if a isn't in the range 1 to 10. Thus the second clause only executes if a isn't in the range 1 to 10 since any value not in 1 to 10 is not in 1 to 5. Tricky isn't it!

For more on ranges see the for loop later in this chapter.

The most general form of a when is using full conditional expressions on clauses. In this case each condition is evaluated from top to bottom and the first to evaluate to true causes its statements to be executed and the when to terminate. In this case the when doesn't need to have an argument and the selection is completely general and can be used to replace complex nested ifs.

For example:

 when {
        a>=1 && a<=10 ->println("1 to 10")
        a<1 || a>5    ->println("not 1 to 10")
   }

This is the same as the previous range example and the first println is executed if a is in the range 1 to 10 and the second is printed if a is not in 1 to 10. As described earlier, the second condition is not a typing mistake, but it is very misleading.

kotlinlogo

Testing For Type

You can even use objects in a when, but in this case the test is for equality of reference, not type. That is, the clause that is executed is the one that has a reference to the same object. For example:

when(obj1){
     obj2->println("same object")
     else->println("different object")
}

prints the message same object if obj1 and obj2 reference the same object, i.e. if obj1==obj2.

If you want to test for equality of type then you have to use the fact that you can use a general expression, for example:

when(obj){
 is MyClass1 ->obj.doMethod()
 }


Last Updated ( Monday, 05 July 2021 )