A close look at Kotlin's "let"
let is a pretty useful function from the Kotlin standard library defined as follows:
fun <T, R> T.let(f: (T) -> R): R = f(this)
You can refer to a previous article I wrote if you want to understand how this function works, but in this post, I’d like to take a look at the pros and cons of using let.
let is basically a scoping function that lets you declare a variable for a given scope:
File("a.txt").let {
// the file is now in the variable "it"
}
There is another subtle use of let when applied to a nullable reference. The ?. operator lets you make sure that the code in scope is only run if the expression is not null:
findUser(id)?.let {
// only run if findUser() returned a non null value
}
After going back and forth about whether this idiom is superior to a simple null test, I am slowly leaning to abandoning it in favor of an if for the following reasons:
-
This idiom is only useful if you want to do an
ifthat doesn’t have anelsebranch. I tend to view such constructs as suspicious sinceifwithout anelsecan be a source of bugs. -
This idiom introduces a renaming. Either you use the default lambda syntax, in which case the renamed variable is implicitly called
it, or you explicitly name the argument:
val user = findUser(id)
user?.let { foundUser ->
// ...
}
This can occasionally be useful but sometimes, I just don’t feel like being forced to rename my variable.
- Following the previous point,
ifdoesn’t impose a renaming but Kotlin’s smart casting guarantees that you won’t have any surprise:
val user = findUser(id)
if (user != null) {
// user is now a non null reference
}
Also, the fact that no new name was introduced and the variable keeps its name user the entire time improves readability in my opinion.
So for these reasons, I tend to default to a good old if these days. None of these arguments are deal breakers, it’s mostly a stylistic preference at this point. Let’s see if I’ll change my mind over the next few months.