Recently, while working with Kotlin (version 1.3.50
), a colleague and I recognized
that we were unable to predict, in what cases,
and in what way (error or just a recommendation),
the IDE (IntelliJ IDEA version 2019.2.1
) does complain about non-exhaustive when expressions.
So I ran a short experiment, of which I'll present the results here.
The general test pattern looks as follows:
fun singleExperiment(x: EnumOrClass) {
when (x) {
Foo.A -> {
someFunction()
}
}
}
So, the first thing to compare is x
being
an instance of a derived class (passed as base-class reference)
or an enum:
enum class Foo { A, B }
open class Base
class Derived1 : Base()
class Derived2 : Base()
Also someFunction
can return a value Unit
or some actual type:
fun printSomething() = println(42)
fun returnSomething(): Int = 42
The third thing to explore is whether it makes a difference to assign the expression to a variable:
val y = when (x) {
...
}
This may sound absurd, but please bear with me. It will become relevant soon.
Last, we will check if using let
in the following way changes things:
x.let {
when (it) {
...
}
}
So, we have 4 binary dimensions in our experiment space.
E
/C
= enum or class (type ofx
)N
/L
= normal or let (wayx
is used)S
/A
= statement or assignment (usage ofwhen
expression)U
/V
= unit or value (someFunction
's return type)
The result of each possible combination can be:
O
= OKR
= Recommendation onlyF
= Failure (compilation error)
Let's explore all 16 corners of this hypercube one by one.
The given recommendation looks as follows:
The error message looks as follows:
That was interesting and somewhat surprising (at least to me).
To finalize, here is a summary table to of the results:
e/c | n/l | s/a | u/v | o/r/f |
---|---|---|---|---|
enum | normal | statement | unit | recommendation |
class | normal | statement | unit | ok |
enum | normal | statement | value | recommendation |
class | normal | statement | value | ok |
enum | let | statement | unit | recommendation |
class | let | statement | unit | ok |
enum | let | statement | value | failure |
class | let | statement | value | failure |
enum | normal | assignment | unit | failure |
class | normal | assignment | unit | failure |
enum | normal | assignment | value | failure |
class | normal | assignment | value | failure |
enum | let | assignment | unit | recommendation |
class | let | assignment | unit | ok |
enum | let | assignment | value | failure |
class | let | assignment | value | failure |
You can find the full source code to play around with here.
Thanks to very helpful people on reddit (1, 2) we can read an explanation for these observations there. They show the pattern behind the behavior that seems chaotic when only observed superficially like here.