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

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

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


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 focus. 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.


and you want to add a horn to it.

Here's the code for doing this.

val pug: Pug = Pug()
val hornyPug: HornyPug = putHornOn(pug)
fun putHornOn(): HornyPug {
   // put horn logic
   return hornyPug

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


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

Let's re-write this using run

val pug: Pug = Pug()
val hornyPug: HornyPug = { putHornOn(this) }

Here's re-write with let

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:

public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T, R> 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.


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)


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


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


Here's the code:

val pug: Pug = Pug()
// after barking, pug is still pug, nothing changes
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

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

Now, using also

val pug: Pug = Pug()
val stillPug = pug.also { it.bark() }

2b. function definition

Take a look at the Standard.kt for the how apply and also are written:

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.


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.

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


  • 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:

    val file = File()

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.

    File().perform {

In this case, performIt will work too:

    File().perform {

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,, and to Crashlytics.

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

    user.performIt {

The perform() will work too.

    user.perform {

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.

    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.

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

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
    fun createFile_setMode_returnRootPath(): String {
        val file = File()
        val rootPath = findRootPath(file)
        return rootPath

re-write using magic functions:

    fun createFile_setMode_returnRootPath(): String {
        return File()
            .perform {
            .transformIt { findRootPath(it) }

Hope it helps!

Bonus Unicorn Pug.


All pugs are taken from freepik, no pugs are hurt in the making.