Kotlin: Scope functions
Tags: kotlin, scopefunction, android, functiontype
Published: 2020-06-04 10:25:21

#Prerequisite/Previous articles:
1. [Kotlin: Function type, higher order function, function literal, lambda expression and an anonymous function](https://dev.to/srdpatel/kotlin-function-type-function-literal-lambda-expression-and-anonymous-function-lbd)
2. [Kotlin: Extension function and Receiver type](https://dev.to/srdpatel/kotlin-extension-function-1dd7)
3. [Kotlin: Inline function](https://dev.to/srdpatel/kotlin-inline-function-olf)

#In a hurry?
You can jump to the _**conclusion**_ section and _**play the concept**_.

#Recap

* We can access the receiver type from the business logic of an extension function through the keyword: _this_
* We can omit the keyword: _this_
* If a lambda has only one parameter, we can access that argument using the keyword: _it_

## Why scope functions?

To make the code more concise!

## How does the scope function make the code more concise?

Let us understand it by an example:

{% kotlin https://pl.kotl.in/lgETMgNR4 %}

As you can see, we could avoid an extra variable. Moreover, we can also omit _this_ keyword as below:

{% kotlin https://pl.kotl.in/fKscMORoX %}

That was neat and clean. Isn't it?

Let us understand our first scope function: _with_

## With

### Definition

```kotlin
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    /*...*/
    return receiver.block()
}
```
Let us examine the definition.

`Inline`

We use the _inline_ keyword for the higher order function to avoid a function object creation, memory allocation and runtime overhead.

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

1. It is a generic function.
2. It can have anything as the first parameter. We can pass any instance as the first argument.
3. Second parameter is a function type, named as `block`.
4. `block` is an extension function.
5. The receiver type of the `block` is whatever we pass as the first argument to the scope function: _with_.
6. We can access the receiver type `T` from extension function `T.() -> R` using the keyword: _this_.
7. The function type parameter is the last parameter in the higher order function _with_. That means, we can pass our function literal between curly braces as an argument after the _with_ function call parentheses.
8. The return type of both the function type parameter and the scope function itself are same: `R`.
9. The return type `R` is generic. That means, whatever our function literal (that we pass as an argument to our _with_ function) returns, will be the return of our _with_ function.
10. In function literals, the last statement gives return.

So, using _with_, we can perform multiple operations on an object without explicitly writing the name of the object or without taking another variable.

However, If the variable is nullable, we cannot avoid that _this_ keyword in _with_.

Suppose we were getting a nullable value in our last example from below function:

```kotlin    
private fun getEvenOrNull(randomNumber: Int): Int? =
   if (randomNumber.rem(2) == 0) randomNumber else null
```
Handling a nullable variable using _with_ would look like below:

{% kotlin https://pl.kotl.in/zpQJ21irM %}

That doesn't look good! There must be a “nullability check” before we perform anything on a “nullable” variable.

Using another scope function called _let_, we can perform the “nullability check” and it also reduces the code than above and make it more pretty like below:

{% kotlin https://pl.kotl.in/EVmOWSnQx %}

So, let us examine: _let_

## let

### Definition

```kotlin
public inline fun <T, R> T.let(block: (T) -> R): R {
    /*...*/
    return block(this)
}
```

`T.let`

We know about an extension function. `T` represents generics here. So, _let_ is a generic extension function. That means, we can use _let_ for any object. It is a member function for every class.

`T.let(block: (T) -> R): R`

Facts:

1. `let` is a higher order function because it has a function type parameter.
2. `let` is also an extension function with a generic receiver type `T`.
3. The receiver type `T` is also a parameter of the function type `block` here.
4. `block` is our function type parameter of the `let` function. We can pass a function type argument using function literal, lambda expression or an anonymous function. 
5. Because the `let` function is generic and it has only one parameter which is also a generic, mostly we use function literal to pass as a function type argument.
6. The function type parameter `block` is the only parameter of a higher order function `let` and the function type has also only one parameter `(T)` which is also the receiver type. So, while calling `let`, we can omit the function call parentheses, the parameter of the function type and the arrow `->`. We will just write our business logic between curly braces and we can access the parameter `(T)` of the function type `block`, using the keyword: `it`.
7. So, we access the receiver type as well as parameter of the function type inside the `let` block using the keyword: `it`.
8. The return type `R` is generic. The `let` function returns whatever our function literal (that we pass as a function type argument for the let function) returns.

### Why _let_?

Because, we don't like that _this?._ for a "nullable variable" multiple times!

1. To provide “nullability check”.
2. To introduce chain operations.

Wait. What? Chain operations? Let us understand what it is.

Suppose we have a normal function like below:

```kotlin
fun doSomething(name: String) {
   println("Name from the method doSomething is: $name")
}
```

Now, let us do some multiple random operations like below:

{% kotlin https://pl.kotl.in/2OfhQ0xBZ %}

Now, let us do the same thing using _let_:

{% kotlin https://pl.kotl.in/1-eyzXmno %}

As you can see, using _let_, we could avoid new variables while using the return value from multiple chain operations.

What?! Understanding the example:

Let us see what we have done (how we have used the _let_ function):

1. _let_ is a generic extension function. So, any instance can call it. Here, the _let_ function is called on a nullable _int_ variable.
2. _let_ is also a higher order function. it has only one parameter. The parameter is of function type. The function type parameter has also only one parameter. Hence, we can omit the function call parentheses, the parameter of the function type and the arrow `->`. All we write is just our business logic between curly braces and we access the parameter of the function type (which is also the receiver type of our extension function) using the keyword _it_. 
3. We have done the same. After the function name which is “_let_”, there is our business logic between curly braces. The keyword _it_ represents our _int_ instance for the first _let block_ and a _StringBuilder_ instance for the second and third block.

Few things to note here:

1. The last statement in the _let_ block decides the return type.
2. We are returning the result and not the receiver type itself.
3. We can check the nullability of the receiver type before we proceed.
4. It is an extension function. So, we can chain multiple operations. The return type (last statement) of the previous _let block_ will become the receiver type of next function.
5. When we want to access the receiver type, we can use the keyword _it_ (We have to use _it_ to access the receiver type).
6. We can use any function on the receiver type from the _let block_ using the keyword: _it_.
7. We can pass the receiver type to another function within the let block using the keyword: _it_.

## With Vs Let

If there is a nullable value or chain operations, use _let_. Otherwise, use _with_ because we can omit the keyword _this_.

Can't we have a function that can omit the keyword _this_ like a _with_ function and support nullability check and chain operations like _let_?

Yes! Our next scope function _run_ is a hybrid product which has power of both _let_ and _with_. 

Let us study: _run_

## Run

Below is the definition of the run function.

```kotlin
public inline fun <T, R> T.run(block: T.() -> R): R {
   /*...*/
   return block()
}
```
Similar to the _let_ function, _run_ is also an extension function and a higher order function. Hence, it also uses the keyword _inline_ to avoid the function object creation.

The differences between _let_ and _run_ functions are:

1. The function type parameter
2. Return type

Let us examine it.

`T.run(block: T.() -> R): R`

1. The receiver type of an extension function and its function type is same: `T`. That means, we can access the receiver type using the keyword: _this_.
2. The keyword _this_ can be omitted when we want to call any function on it that reduces the code even more.
3. It seems that the _run_ function has combined the power of _with_ and _let_. Or maybe we can say it is a _with+_ version! _With_ was lacking the pros of an extension function (nullability check and chain operations) which the _run_ function satisfies.

Instead of _let_, If we use _run_ and rewrite the same function we have written earlier for _let_, it would look like below:

{% kotlin https://pl.kotl.in/_HjqodkY3 %}

There are few things common between _run_ and _let_ as below. It will help us in deciding when to use them:

1. Both are extension functions.
2. Last statement is the return type.
3. We can check the nullability before we proceed.
4. Extension functions are helpful for chain operations.

However, there is a small but important difference between them as below. It will help us in selecting the right scope function.

In _let_, we access the receiver type using the keyword _it_ and it cannot be omitted. However, in _run_, we access the receiver type using the keyword _this_ and it can be omitted sometimes.

So, if we are not passing the receiver as an argument, we better use _run_ because it reduces the code. 

Considering above facts, we can rewrite our last example in a better way like below:

{% kotlin https://pl.kotl.in/bWzUfvTb8 %}

`StringBuilder(toString())` looks more concise than `StringBuilder(it.toString())`.  

Similarly, `append(" test")` looks more concise than `it.append(" test")`.

However, wouldn’t it be more concise if we can replace all _$this_ by _$it_?

But how? We have to use _this_ to refer to the context object in _run_.
Correct, but not for "_also_”. We can use _it_ to refer to the context object while using _also_.

**Then, how is it different from _let_?**

“_also_” returns the object itself whereas the last statement is “return type” for _let_.

Ok, enough theory! Show me code!

## Also
### Definition

```kotlin
public inline fun <T> T.also(block: (T) -> Unit): T {
   /*...*/
   block(this)
   return this
}
```

`T.also`

It is an extension function. That means, we can use it for “nullability check” before we proceed to work on a nullable value.

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

`(block: (T) -> Unit)`

`block` is a function type parameter.

`block` has one and only parameter `(T)`.

We know that if the function type has one and only argument, we can access the argument using the keyword _it_.

`T` , The only parameter of the `block` is also a receiver type here.

So, we will be accessing the receiver type `T` using the keyword: _it_.

The interesting part is, it returns the receiver type itself: `T`

Using _also_, We can rewrite our last example code as below:

{% kotlin https://pl.kotl.in/cFW9SycFP %}

As shown in the example, _also_ returns the object itself despite anything written in it's block and it uses _it_ to refer to the context object.

So, It uses _it_ to refer to the context object. That means, if we need to call some methods on the context object, we will have to use _it_ like below:

{% kotlin https://pl.kotl.in/4henvQOwa %}

So, we had to use _it_ while calling a function on the context object from _also_ block similar to _let_. 

**Can we omit _it_ to make the code even more concise?** 

Yes! By using _apply_ instead of _also_!

Similar to _run_, _apply_ also uses _this_ to refer to the context object. However, unlike _run_, being a sibling of _also_, _apply_ returns the context object itself.

Let us examine _apply_.

##Apply

###Definition

```kotlin
public inline fun <T> T.apply(block: T.() -> Unit): T {
   /*...*/
   block()
   return this
}
```

`T.apply`

It is an extension function. Useful for “nullability check”.

`block: T.() -> Unit`

`block` is a function type parameter.

The receiver type of an extension function `T.apply` and it's function type parameter `block` is same: `T`.
And we know that we can refer to a receiver type using the keyword: _this_
And we also know that we can omit the keyword _this_ while calling a function on it.

`T.apply(block: T.() -> Unit): T`

As we can see, it returns the receiver type itself.

Let us see how we can include _apply_ in our last example:

{% kotlin https://pl.kotl.in/40U4Bx8MX %}

# Conclusion:

We have scope functions to make the code more concise.
All scope functions can be categorized or differentiated by two facts:

1. The way to refer to the context object (this or it)
2. Return type (the object itself or the last statement)

Using these two facts, we can decide which scope function to use for a particular situation.

1) If we need last statement as a return, we have:

* T.run
* T.let
* with

Anything that the _with_ can do, can be done by _T.run_ also. Clearly, _T.run_ wins here because of it's added “nullability check” and “chain operation” capabilities.

_T.run_ is better than _T.let_ if we are not passing the receiver type as an argument to another function.

2) If we want to return the object itself, we have:

* apply (uses _this_ to refer to the object)
* also (uses _it_ to refer to the object)

Same as the comparison between _T.run_ Vs _T.let_; _apply_ is better than _also_ if we are not passing the context object as an argument to another function.

## Play an overview of this article:

{% kotlin https://pl.kotl.in/kZJ0uXHK1 %}

That’s all! If you find this article helpful, you can click on that heart icon 😉

Applauds and creative critics are always welcome 😇. Your ❤ motivates me to write more articles.

Thanks for reading the article! Have a great day 😇.

# Relevant previous articles
[Inline function](https://dev.to/srdpatel/kotlin-inline-function-olf)
[Extension function and Receiver type](https://dev.to/srdpatel/kotlin-extension-function-1dd7)
[Function type, Function literal, Lambda expression and Anonymous function]
(https://dev.to/srdpatel/kotlin-function-type-function-literal-lambda-expression-and-anonymous-function-lbd)

You can follow me to get the notification when I publish a new article.

# Let us be Connected

[https://www.linkedin.com/in/srdpatel](https://www.linkedin.com/in/srdpatel)

[https://twitter.com/iSrdPatel](https://twitter.com/iSrdPatel)

Tags: kotlin, scopeFunctions, android