Understanding Kotlin's Scope Functions
Tags: kotlin, android, mobile
Published: 2024-04-15 08:33:48

## What are Scope Functions?
Scope Functions are a part of Kotlin standard library. It executes a block of code within that context of an object. Using these functions on an object with lambda expression, it provides a temporary scope for that object which is either accessible by _it_(default) or _this_, depending on function type. With this we can access those objects without their names. Thereby it makes the code simple, clean and easily readable. There are 5 different types of scope functions in Kotlin: let, _with_, _run_, _also_ & _apply_.

**When to choose what?** 
To choose the right function for your requirement, please check the below table.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4dkxy3uxlubp3ulqlmh.png)

**let:**
_let_ is primarily used along with a safe call operator (?.) to prevent _NullPointerException_. It will execute the block of code only if the object is not null.

```
fun main (){
	val name: String? = null
	println(name!!.length)
}
```

**Output:**
`Exception in thread "main" java.lang.NullPointerException`

**Using let function:**

```
fun main (){
	val name: String? = null
	name?.let{
        println(name!!.length) //statement will not execute 
                               //as name is null
    }
}
```

**with:**
_with_ is used for calling functions on context objects without providing the lambda result. It is used to access members and methods of an object without having refer to it.

**Using with function:**
```
class Person {
    var name: String = ""
    var age: Int = 0
}

fun main() {
    val person = Person()
    with(person) {
        name = "Vijay"
        age = 30
        println("Name: $name, Age: $age")
    }
}
```
**Output:**
`Name: Vijay, Age: 30`

Inside the with block, you can directly access the properties (name and age) of the person object without explicitly referencing person. This can lead to more concise and readable code, especially when performing multiple operations on the same object.

**run:**
_run_ is a combination of 'let' and 'with' functions. Imagine a null value is assigned to an object and we want to prevent it from NullPointerException. In this case, we can use _run_ function with that object. 

**Using run function:**

```
class Person {
    var name: String = ""
    var age: Int = 0
}

fun main() {
    val person = Person()
    val result = person.run {
        name = "Vijay"
        age = 30
        "Name: $name, Age: $age"
    }
    
    println(result)
}
```
**Output:**
`Name: Vijay, Age: 30`

The run function also returns the result of the last expression inside its block, which is a string containing the name and age of the person.

**also:**
_also_ is used where we want to perform additional operations when we have initialized the object member. 

**Using also function:**

```
class Person {
    var name: String = ""
    var age: Int = 0
}

fun main() {
    val person = Person()
    val result = person.also {
        it.name = "Vijay"
        it.age = 30
    }.let {
        "Name: ${it.name}, Age: ${it.age}"
    }
    println(result)
}
```
**Output:**
`Name: Vijay, Age: 30`

The _let_ function is called on the returned object (person). It takes a lambda with the parameter _it_, which refers to the object returned by _also_. Inside the _let_ block, a string is created using the properties of the object returned by _also_. The result is assigned to the result variable.

**apply:**
_apply_ is mostly used for initializing the objects. It is also used to configure specific attributes of that object. 

**Using apply function:**

```
class Person {
    var name: String = ""
    var age: Int = 0
}

fun main() {
    val person = Person()
    val result = person.apply {
        name = "John"
        age = 30
    }.let {
        "Name: ${it.name}, Age: ${it.age}"
    }
    println(result)
}

```
**Output:**
`Name: Vijay, Age: 30`

The difference between _apply _and _also_ is, _apply_ is more focused on modifying and initializing objects and returning them, while _also_ is more about performing side effects or additional actions without altering the object and then returning it.