87

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?

Kanaiya Katarmal
  • 5,974
  • 4
  • 30
  • 56
  • 3
    Related: https://stackoverflow.com/questions/45977011/example-of-the-different-of-run-let-apply-also-and-with-on-kotlin – BakaWaii Sep 09 '17 at 13:41
  • 1
    Your example usage code is different, thus I would conclude that there *is* a difference between the functions. – voddan Sep 10 '17 at 06:06
  • Possible duplicate of [differnce between kotlin also, apply, let, use, takeIf and takeUnless in Kotlin](https://stackoverflow.com/questions/45582732/differnce-between-kotlin-also-apply-let-use-takeif-and-takeunless-in-kotlin) – Bhuvanesh BS May 05 '18 at 08:20

3 Answers3

67

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.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
50

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.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
21
  • 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)
oiyio
  • 5,219
  • 4
  • 42
  • 54