Mastering Kotlin's Scope Functions: let, run, with, apply, and also 🎯
Tags: kotlin, programming, beginners, tutorial
Published: 2023-04-24 14:35:43

Kotlin is well-known for its elegant and concise syntax that improves the overall development experience. One of the powerful features Kotlin brings to the table is scope functions. They allow you to streamline your code, make it more readable, and simplify complex operations. In this blog post, we'll explore the five main scope functions in Kotlin: let, run, with, apply, and also. Buckle up and let's dive in! 🚀

## Let

`let` is an extension function that executes a block of code within the context of the object it's called on. It returns the result of the last expression in the block. It's particularly useful when you want to perform operations on a nullable object, as it enables you to work within a safe, non-nullable context.

```kotlin
val nullableString: String? = "Kotlin is awesome!"
nullableString?.let { 
    println(it.length) // Prints the length of the non-null string
}
```

## Run

`run` is similar to `let`, but it operates within the context of this instead of using it. It's perfect for executing multiple operations on the same object or working with mutable properties. Like `let`, `run` also returns the result of the last expression in the block. 

```kotlin
val result = "Hello, world!".run {
    this.toUpperCase()
    this.reversed()
}
println(result) // Prints "!dlrow ,olleH"
```

## With

`with` is a non-extension function that receives an object as its first parameter and a block of code as its second parameter. It allows you to work within the object's context and returns the result of the last expression in the block.

```kotlin
data class Person(val name: String, val age: Int)

val person = Person("John", 30)
val info = with(person) {
    "Name: $name, Age: $age"
}
println(info) // Prints "Name: John, Age: 30"
```

#### Pro Tip

`with` and `run` are very similar. The main difference being that `run` is a dot method and `with` being a higher-order function. Having `run` be a dot method is actually great with dealing with nullable values! 

```kotlin
data class Person(val name: String, val age: Int)

val person: Person? = Person("John", 30)

val info = with(person) {
    // this will give us issues because person might be null
    "Name: $name, Age: $age"
    // to fix it, we'll have to do this
    "Name: ${this?.name}, Age: ${this?.age}"
    // but the above seems kind of verbose
}
// we can use a safe call before run to clean up our code
val info = person?.run {
    "Name: $name, Age: $age"
}
```

## Apply

`apply` is another extension function that operates within the context of the calling object using `this`. It's handy for configuring or initializing objects, as it returns the object itself after executing the block of code.

```kotlin
data class User(var name: String, var email: String)

val user = User("Jane", "jane@example.com").apply {
    name = "Jane Doe"
    email = "jane.doe@example.com"
}
println(user) // Prints "User(name=Jane Doe, email=jane.doe@example.com)"
```

## Also

`also` is similar to `apply`, but it uses `it` instead of `this` within the block. It's useful for performing side effects or logging without modifying the object. Like `apply`, `it` also returns the object itself.

```kotlin
val numbers = mutableListOf(1, 2, 3, 4, 5).also {
    println("Original list: $it")
    it.add(6)
}
println("Updated list: $numbers")
```

---

Kotlin's scope functions are powerful tools that can simplify your code, make it more readable, and improve your development experience. By mastering let, run, with, apply, and also, you'll be well on your way to becoming a Kotlin expert. Keep exploring and have fun coding! 🌟

Don't forget to follow for more Kotlin insights and tips!