Kotlin: What is the difference between Apply and Also

Kotlin

Kotlin Problem Overview


What is the difference between apply and also. From what I know the following code does the same thing:

apply

val person = Person().apply {
    name = "Tony Stark"
    age = 52
    // More such stuff
}

also

val person = Person().also {
  it.name = "Tony Stark"
  it.age = 52
  // More such stuff
}

Is there any difference and should I use one over the other? Also, are there some cases where one would work and the other won't?

Kotlin Solutions


Solution 1 - Kotlin

TL;DR Difference

The also function takes a lambda in which you refer to the object you called the function on (receiver T) with either it (implicit name) or a custom name.

val person = Person().also {
    it.name = "Tony Stark"
}

With apply, on the other hand, a function literal with receiver is used so inside the passed in lambda you can access the receiver’s members directly, as you see in the following. The receiver can be referenced by this.

val person = Person().apply {
    name = "Tony Stark"
}

also

Declaration:

inline fun <T> T.also(block: (T) -> Unit): T (source)

Calls the specified function block with this (the receiver) value as its argument and returns this (the receiver) value.

apply

Declaration:

inline fun <T> T.apply(block: T.() -> Unit): T (source)

Calls the specified function block with this value as its receiver and returns this (the receiver) value.

when to use what

Usage examples are explained in this thread.

Solution 2 - Kotlin

Short answer: also was introduced for semantic reasons.

Long answer:

If you use apply you always refer to the receiver with this.

val person = Person().apply {
    name = "Tony Stark" // this. can be omitted
    age = 52 // this. can be omitted
    // ...
}

This way you don't have to repeat person several times as shown here:

person.name = "Tony Stark"
person.age = 52

If the block becomes longer you may want to give this a name. That's why also was introduced. Now you can refer to the receiver either by it or an explicit name. This is especially useful if you want to use another name than (in this case person) before:

val person = Person().also { newPerson ->
  newPerson.name = "Tony Stark"
  newPerson.age = 52
  // ...
}

So, depending on how well you code should be readable you can always use one or the other.

Solution 3 - Kotlin

  • Both function returns receiver object itself.
  • They differ in accessing the receiver object.

enter image description here

It is your decision which one to use. However, in Kotlinlang's website https://kotlinlang.org/docs/reference/scope-functions.html, there is a convention for their usage

Use also for additional actions that don't alter the object, such as logging or printing debug information.

val numbers = mutableListOf("one", "two", "three")
 numbers
     .also { println("The list elements before adding new one: $it") }
     .add("four")

The common case for apply is the object configuration.

val adam = Person("Adam").apply {
    age = 32
    city = "London"        
}
println(adam)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKanaiya KatarmalView Question on Stackoverflow
Solution 1 - Kotlins1m0nw1View Answer on Stackoverflow
Solution 2 - KotlinWilli MentzelView Answer on Stackoverflow
Solution 3 - KotlinoiyioView Answer on Stackoverflow