I was surprised today to learn that this take on apparently idiomatic code fails:
class QuickTest {
var nullableThing: Int? = 55
var nullThing: Int? = null
@Test
fun `test let behaviour`() {
nullableThing?.let {
print("Nullable thing was non-null")
nullThing?.apply { print("Never happens") }
} ?: run {
fail("This shouldn't have run")
}
}
}
It happens because, combined with implicit return, nullThing?.apply{...}
passes null to the let, and therefore the elvis operator evaluates on null and runs the second block.
This is pretty horrible to detect. Do we have an appropriate alternative beyond conventional if/else
without this pitfall?
You could use also
instead of let
. also
will return nullableThing
, whereas let
will return whatever the lambda returns.
See this article: https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84 (point "3. Return this vs. other type").
Your case is a candidate for also
thematic. Compare two block
actions:
fun <T> T.also(block: (T) -> Unit): T
fun <T, R> T.let(block: (T) -> R): R
nullableThing?.also {
print("Nullable thing was non-null")
nullThing?.apply { println("Never happens") }
} ?: run {
fail("This shouldn't have run")
}
Another idiomatic way is to use when
statement
when (nullableThing) {
null ->
print("Nullable thing was non-null")
nullThing?.apply { println("Never happens") }
else -> fail("This shouldn't have run")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With