How to use Kotlin's 'it also let apply run'

# Kotlin magick
Kotlin is being officially used in Android development, and every Android developers are probably busy picking up Kotlin. That includes me.

```java:hello.java
print "hello world"
```

I stumbled upon these few magical methods during my Kotlin journey:

```java:Animal.java
    class Animal {}
```
```java:Dog.java
    class Dog extends Animal {}
```

```kotlin:temp.java
    .also()
    .let()
    .apply()
    .run()
```

They are magical because they can perform some Kotlin magics and at the same time greatly resemble English words. Thanks to the resemblance, I even tried forming sentence using them. Let's assume Apply is a person name, I can make a grammatically correct English sentence with them: `it also let Apply run`.

Nonsense apart, I find it really hard to understand the usage based on their names.

There are also `with` and other friends in the `Standard.kt`, but I want to keep this post focused. So I'm leaving out the rest. Actually I'm just lazy to cover them all ಠ_ಠ. I want to go do some snowboarding instead, it's winter already, yay! ^3^

---

## 1. let and run transform
#### 1a. pug analogy, part I
There's a famous saying "to begin learning is to begin to forget". So let's forget about `it also let apply run` for a second. Ok, I just made that up. Let's start with a simple requirement.

Let's say you have a `pug`.

<img src="https://i.imgur.com/ToWqEup.png" width="150px"/>

and you want to add a horn to it.

Here's the code for doing this.

```kotlin
val pug: Pug = Pug()
val hornyPug: HornyPug = putHornOn(pug)
```

```kotlin
fun putHornOn(): HornyPug {
   // put horn logic
   return hornyPug
}
```

Now it has became a pug with horn, let's call it `hornyPug` ಠ‿ಠ:

<img src="https://i.imgur.com/OBKDqZL.png" width="150px"/>

From `pug` to `hornyPug`, the original `pug` has been changed. I call this "transformation".


Let's re-write this using `run`

```kotlin
val pug: Pug = Pug()
val hornyPug: HornyPug = pug.run { putHornOn(this) }
```

Here's re-write with `let`

```kotlin
val pug: Pug = Pug()
val hornyPug: HornyPug = pug.let { putHornOn(it) }
```

#### 1b.Function definition

Take a look at the `Standard.kt` for the how `let` and `run` is written:

```kotlin
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T, R> T.run(block: T.() -> R): R = block()
```

It can be hard to read at first, let's only focus on the `return type` for now:
- `R` is the return type
- `T` is the input or type of the calling object.

What it means is `T` type will turn into `R` type after `let` or `run`.

In the case of our example, `pug` is `T`, `hornyPug` is `R`.

<img src="https://i.imgur.com/GoeRwHu.png" width="350px"/>

#### 1c. Key take away: 
- whenever transformation happens, use `let` or `run`

---

## 2. apply and also doesn't transform
#### 2a. pug analogy, part II
Let's do the same thing for this.

Say you have a pug in a trash can. (hint: trash can is not important)

<img src="https://i.imgur.com/ofsH4Jw.png" width="150px"/>

You want it to `bark()`: "woof!"

<img src="https://i.imgur.com/Zui4Ew0.png" width="200px"/>

After barking, it's still the same old pug.

<img src="https://i.imgur.com/ofsH4Jw.png" width="150px"/>

Here's the code:

```kotlin
val pug: Pug = Pug()
pug.bark()
// after barking, pug is still pug, nothing changes
```

```kotlin
class Pug {
    fun bark() {
        // Log.d("pug", "woof!") // print log to Android Studio
        // no return, which means, return Unit in Kotlin
    }
}
```

Before and after `.bark()`, `pug` is still `pug`, nothing changes. 

Let's re-write this using `apply`

```kotlin
val pug: Pug = Pug()
val stillPug: Pug = pug.apply { bark() }
```

Now, using `also`

```kotlin
val pug: Pug = Pug()
val stillPug: Pug = pug.also { it.bark() }
```
#### 2b. function definition
Take a look at the `Standard.kt` on how `apply` and `also` are written:

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

Notice that now it doesn't have `R` type, because `T` the original object type, is returning `T` after `apply` or `also`.

<img src="https://i.imgur.com/tIyJYHW.png" width="450px" />

In our case, `T` is `pug`, and it remains the same before and after.

#### 2c. Key take away

When there is no transformation, use `apply` or `also`.

---

## 3. A little confusing, how about renaming?
Most of the developers who I talked to find `it also let apply run` naming to be confusing. I am wondering if it would be easier to understand if we have a better naming?

Let's try this, Kotlin allows us to `import` a method name as another name.

```kotlin
import kotlin.apply as perform
import kotlin.run as transform
import kotlin.also as performIt
import kotlin.let as transformIt
```

Explanation:
- If there is no transformation, we use `perform()` or `performIt()`
- If there is transformation, we use `transform()` or `transformIt()`

Let's check the example use case.

#### 3a. configuration example - perform()

If we need to create a file, and configure it:

```kotlin
    val file = File()
    file.setReadable(true)
    file.setExecutable(true)
    file.setWritable(true)
```

In the code above, we configure `file` by running 3 lines of code. At the end, `file` doesn't change into something else. So `no transformation`. We use the `perform` version.

```kotlin
    File().perform {
        setReadable(true)
        setExecutable(true)
        setWritable(true)
    }
```

In this case, `performIt` will work too:

```kotlin
    File().performIt {
        it.setReadable(true)
        it.setExecutable(true)
        it.setWritable(true)
    }
```

But `perform` is better, since we don't really need `it`

#### 3b. perform task on an object - performIt()
If we need to perform a task on an object, for example, when a crash happens, we want to send the `user.id`, `user.name`, and `user.country` to `Crashlytics`.

In this case, there is `no transformation` going on. I choose the `performIt()` version.

```kotlin
    user.performIt {
        Crashlytics.sendId(it.id)
        Crashlytics.sendName(it.name)
        Crashlytics.sendCountry(it.country)
    }
```

The `perform()` will work too.

```kotlin
    user.perform {
        Crashlytics.sendId(id)
        Crashlytics.sendName(name)
        Crashlytics.sendCountry(country)
    }
```

It's a matter of preference, whether to choose `perform` or `performIt`. I don't think we should waste too much time thinking about which to be chosen.

#### 3c. creating view holder - transform

Let's say we have a method to create `ViewHolder`.

```kotlin
    fun create(parent: ViewGroup): PugViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_pug, parent, false)
        return PugViewHolder(itemView)
    }
```

We can see that `itemView` is `transformed` into `PugViewHolder` at the end. So we can use the `transformIt` version.

```kotlin
    fun create(parent: ViewGroup): PugViewHolder {
        return LayoutInflater.from(parent.context).inflate(R.layout.item_pug, parent, false).transformIt {
            PugViewHolder(it)
        }
    }
```

Again, the `transform()` version will work too. So I'm not writing 3d.

---

## 4. All working together

Consider a case where we need to
1. create a file
2. set the file to readable, writable, executable
3. return the root path of the file

```kotlin
    fun createFile_setMode_returnRootPath(): String {
        val file = File()
        file.setReadable(true)
        file.setExecutable(true)
        file.setWritable(true)
        val rootPath = findRootPath(file)
        return rootPath
    }
```

re-write using magic functions:

```kotlin
    fun createFile_setMode_returnRootPath(): String {
        return File()
            .perform {
                setReadable(true)
                setExecutable(true)
                setWritable(true)
            }
            .transformIt { findRootPath(it) }
    }
```

With the renaming, it's easier to understand, don't you think so? 
It is at least for me.

---


Thanks for reading, if you made it this far, I present you a....

Bonus Unicorn Pug.
<img src="https://i.imgur.com/IsHDGV6.png" width="200px"/>

All pugs are taken from [freepik](https://www.freepik.com/free-vector/fun-set-of-pugs-with-costumes_1357330.htm#term=dog&page=1&position=36), no pugs are hurt in the making.