# An In-Depth Guide to Kotlin's Scoped Functions: let, run, with, also, apply

**Kotlin**, a modern programming language is well known due to its simplicity, conciseness, and safety. One of the features that make **Kotlin** stand out is its set of scoped functions: `let`, `run`, `with`, `also`, and `apply`. These functions enable developers to manipulate objects and handle nullable values concisely and expressively. In this article, we will explore each of these functions and understand their unique purposes with detailed examples.

---

## Let

The `let` function is particularly useful for working with nullable objects. It allows us to perform operations on an object if it's not null and returns the result of the operations. If the object is null, `let` does nothing and returns `null`. The syntax for `let` is as follows:

```kotlin
fun <T, R> T?.let(block: (T) -> R?): R?
```

**Where:**

* `T`: The type of the object to be processed.
    
* `R`: The type of the result of the operations.
    
* `block`: The lambda function that takes the non-null object as an argument and returns the result.
    

Let's illustrate this with an example. Imagine we have a nullable `String` representing a user's name, and we want to print its length only if it's not null:

```kotlin
val userName: String? = "John Doe"
userName?.let { name ->
    println("User's name is $name, and its length is ${name.length}")
}
```

In this example, the lambda function inside `let` will be executed only if `userName` is not `null`. If `userName` is `null`, nothing happens, and the code inside `let` it skip.

---

## Run

The `run` function is useful when we want to perform multiple operations on an object. It simplifies the code by providing a temporary scope where we can access the properties and functions of the object directly without the need to qualify them. The syntax for `run` is as follows:

```kotlin
fun <T, R> T.run(block: T.() -> R): R
```

**Where:**

* `T`: The type of the object to be processed.
    
* `R`: The type of the result of the operations.
    
* `block`: The lambda function with the receiver (denoted by `T.()`) that operates on the object and returns the result.
    

Let's consider an example where we have a data class `Person` and we want to manipulate its properties within a temporary scope:

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

val person = Person("Alice", 30)
val modifiedPerson = person.run {
    age += 5
    this // Return the modified person object
}
println("Modified person: $modifiedPerson")
```

In this example, we use `run` to access and modify the `age` property of the `person` object within a temporary scope. The modified person object is then stored in `modifiedPerson`, and we print the result.

---

## With

The `with` function similar to `run`, but it is a standard library function rather than an extension function. It allows us to access the properties and functions of an object directly, just like `run`. The syntax for `with` is as follows:

```kotlin
fun <T, R> with(receiver: T, block: T.() -> R): R
```

**Where:**

* `receiver`: The object on which the operations will be performed.
    
* `R`: The type of the result of the operations.
    
* `block`: The lambda function with the receiver (denoted by `T.()`) that operates on the object and returns the result.
    

Here's an example using the same `Person` data class as before:

```kotlin
val person = Person("Bob", 25)
val result = with(person) {
    age += 3
    name.toUpperCase()
}
println("Modified person: $person")
println("Result: $result")
```

In this example, we use `with` to modify the `age` property of the `person` object and return the uppercase version of the `name` property.

---

## Also

The `also` function is handy when we want to perform additional operations on an object and retain the original object. It returns the original object after performing the specified operations. The syntax for `also` is as follows:

```kotlin
fun <T> T.also(block: (T) -> Unit): T
```

**Where:**

* `T`: The type of the object to be processed.
    
* `block`: The lambda function that takes the object as an argument and performs the additional operations.
    

Let's see an example where we have a list of integers, and we want to filter out the odd numbers and print the modified list along with the original list:

```kotlin
val numbers = listOf(1, 2, 3, 4, 5)
val filteredNumbers = numbers.filter { it % 2 == 0 }
    .also { modifiedList ->
        println("Modified List: $modifiedList")
    }
println("Original List: $numbers")
```

In this example, we use `also` to print the modified list after filtering out odd numbers while still retaining the original list.

---

## Apply

The `apply` function is useful for configuring the properties of an object during its initialization. It returns the object itself after applying the configurations. The syntax for `apply` is as follows:

```kotlin
fun <T> T.apply(block: T.() -> Unit): T
```

**Where:**

* `T`: The type of the object to be processed.
    
* `block`: The lambda function with the receiver (denoted by `T.()`) that configures the properties of the object.
    

Here's an example where we create a `Person` object and configure its properties using `apply`:

```kotlin
val newPerson = Person("", 0).apply {
    name = "Eve"
    age = 28
}
println("New person: $newPerson")
```

In this example, we use `apply` to create a `Person` object with default values and then configure its `name` and `age` properties within the same scope.

---

## Conclusion

Kotlin's scoped functions (`let`, `run`, `with`, `also`, and `apply`) are powerful tools that contribute to writing concise and readable code. By leveraging these functions, developers can handle nullable objects, perform operations on objects with a temporary scope, configure object properties during initialization, and perform additional operations while retaining the original object. Understanding and effectively using these functions can lead to cleaner and more expressive Kotlin code.

---

That's it for today. Happy Coding...

---

> If get to know something new by reading my articles, don't forget to endorse me on [LinkedIn](https://www.linkedin.com/in/rommansabbir/)
> 
> Read about [SOLID Principles](https://rommansabbir.com/series/solid-principles)
> 
> Read about [Android Development](https://rommansabbir.com/series/android)
