I am confused with kotlin smart casts. In my opinion if(condition) / else
is equivalent to when(condition) true -> /false ->
, however the smart cast isn't working for my when expression.
I am using kotlin 1.5.30
data class Person(val name: String)
data class Address(val id: String, val person: Person?)
fun getPersonFromAddress(address: Address?): String {
return if (address?.person != null) {
address.person.name
} else {
"Not found"
}
}
fun getPersonFromAddress(address: Address?): String {
return when (address?.person != null) {
true -> address.person.name // <-- Does not compile
false -> "Not found"
}
}
CodePudding user response:
Because of the way it analyzes it, the if expression translates to a when expression that looks like this:
fun getPersonFromAddress(address: Address?): String {
return when {
address?.person != null -> address.person.name
else -> "Not found"
}
}
which will compile.
A when
with an argument is different than when
without an argument. The expression in the argument is evaluated first, one time only. Then that result (not the expression) is compared against each case. So in terms of how it is evaluated, it is a step removed from being the same as the if/else.
As @broot mentioned in the comments, you can also defer the null-check to the when case like this, and the smart-cast will work because it's checking it at that branch:
fun getPersonFromAddress(address: Address?): String {
return when(address?.person) {
null -> "Not found"
else -> address.person.name
}
}
If you were to translate your attempt at a when statement with condition to if/else syntax, it would look like this:
fun getPersonFromAddress2(address: Address?): String {
val condition = address?.person != null
return if (condition) {
address.person.name
} else {
"Not found"
}
}
which will also not compile.
I suppose the reason for this is the complexity of what the compiler would have to analyze to smart cast in these conditions could grow exponentially by adding the extra indirect check.