Cheat Sheet included
Kotlin Scope Functions Explained
For those who have general knowledge but need a summary, here’s a Scope Functions Cheat Sheet:
Now let’s get into details and examples:
Let
- Reference:
it
- Returns:
lambda result
- Usage: executing code on a non-nullable object
To understand it better, we’ll use a helper function:
fun nonNullablePrint(text: String) {
println(text)
}
It’s a version of println
that requires the String
to be non-nullable.
Since it’s primarily used for safe access to nullable objects, it’s what we’ll do in the example:
class LetExample {
private var text: String? = null
fun printText() {
if (text != null) {
// text in reality still has a nullable scope here:
nonNullablePrint(text) // compilation error
}
}
}
Even though we’ve checked whether text
is nullable, we still get a Compilation Error. Why? Because text
is a mutable property and could’ve changed after the if
check.
We can fix it using let
that changes the scope to the current value of text
instead of the variable itself:
class LetExample {
private var text: String? = null
fun printText() {
text?.let { nonNullablePrint(it) } // 100% sure it's non-nullable
}
}
With
- Reference:
this
- Returns:
lambda result
- Usage: multiple function calls on an object
It stands for ‘with this we can do that’. Let’s take a look at the example:
fun noWithExample(list: List<Int>) {
println(list.size)
println(list.sum())
println(list.lastIndex)
println(list.toString())
}
The code can be improved: ‘with list we can print its info’:
fun withExample(list: List<Int>) {
with(list) {
println(size)
println(sum())
println(lastIndex)
println(toString())
}
}
Actually, in this example, we can reduce indentation by moving with the call since it returns lambda result
:
fun betterWithExample(list: List<Int>) = with(list) {
println(size)
println(sum())
println(lastIndex)
println(toString())
}
It’ll return the same result as withExample
Run
- Reference:
this
or-
- Returns:
lambda result
- Usage: object configuration, but with the computed result
It works like a hybrid between with
and let
. Allowing you to run multiple functions on this
object, but being called as an extension function like let
:
class Service(
var address: String = "",
var portNumber: Int = 0,
) {
fun get() = "Getting from $address and $portNumber"
}
fun noRunExample(service: Service) {
service.address = "address.example"
service.portNumber = 8080
val result = service.get()
println(result)
}
We can modify it to use run
:
fun runExample(service: Service) {
val result: String = service.run {
address = "address.example"
portNumber = 8080
get()
}
println(result)
}
It makes the code a bit cleaner. Moreover, it can be used without being called on an object. This way, we can limit the visibility of the Service if it’s a temporary object required to produce a result:
fun runTemporaryExample() {
val result: String = run {
val address = "address.example"
val port = 8080
Service(address, port).get()
}
address // We can't access this val
port // We can't access this val
println(result)
}
Also
- Reference:
it
- Returns:
object
- Usage: additional effects
Let’s say we’re having an adding function. We want to print the produced result each time addition is being done:
fun addNoAlso(a: Int, b: Int): Int {
val result = a + b
println(result)
return result
}
The code is a bit lengthy. We could shorten it with also
:
fun addAlso(a: Int, b: Int): Int = (a + b).also { println(it) }
We end up with 1-liner function!
Apply
- Reference:
this
- Returns:
object
- Usage: object configuration
We can translate its usage to ‘apply this to the object’. Let’s say we have a Car
class, we want to configure with a function:
class Car {
lateinit var name: String
lateinit var brand: String
}
fun configureCarNoApply() {
val car = Car()
car.name = "Super Car"
car.brand = "IT Cars"
}
We can replace it using apply
function for easier access to Car
members:
fun configureCarApply() {
val car: Car = Car().apply {
name = "Super Car"
brand = "IT Cars"
}
}
It works well, especially when we need to configure many fields!
Thanks for reading! If you’ve learned something, please clap and follow me for more!
Based on: