I saw the following comment in a S.O. post, and I'm intrigued:
why don't you use if for null checks?
a?.let{} ?: run{}
is only appropriate in rare cases, otherwise it is not idiomatic – voddan May 15 '16 at 7:29 best way to null check in kotlin?
Why is that construct "only appropriate in rare cases"?
The lead engineer for Kotlin says,
run allows you to use multiple statements on the right side of an elvis operator https://stackoverflow.com/a/51241983/6656019
although I admit that's not actually endorsing it as idiomatic. Both of these posts seem to be from very well respected S.O. Kotlin contributors.
The post that inspired the original comment mentions that the let
part of the expression is important if a
is mutable. In that case, you'll need a?.let{} ?: run{}
instead of if{} else {}
.
I find I like the "let Elvis run" construct. Should I avoid it in most cases?
Thanks for any insight.
In certain computer programming languages, the Elvis operator ?: is a binary operator that returns its first operand if that operand is true , and otherwise evaluates and returns its second operand.
let takes the object it is invoked upon as the parameter and returns the result of the lambda expression. Kotlin let is a scoping function wherein the variables declared inside the expression cannot be used outside.
The Elvis operator in Kotlin is an operator that receives two inputs and returns the first argument if it is non-null or the second one otherwise. It is fancily called the null-coalescing operator. It is a variant of the ternary operator but for null-safety checking. Motivation.
There is no ternary operator in kotlin, as the if else block returns the value.
It's dangerous to conflate foo?.let { bar(it) } ?: baz()
with if (foo != null) bar(foo) else baz()
.
Say you have a function: fun computeElements(): List<Int>? = emptyList()
Consider this code:
val maxElement = computeElements()?.let { it.max() } ?: return println("Max element was $maxElement")
Compared to:
val list: List<Int>? = computeElements() val maxElement = if (list != null) list.max() else return println("Max element was $maxElement")
You may think these are two equivalent forms. However, if you run both, you'll see that the former does not print anything to stdout!
This is because it.max()
returns null
for an empty list (because there is no max element), which causes the right-hand side of the Elvis expression to be evaluated, and so the function return
s early.
In short, ?.let { ... } ?: ...
allows both branches of the "if-else" to be evaluated, which is dangerous. Aside from this form not being readable (if-else
is universally understood, while let-run
is not), subtle bugs can occur.
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