Kotlin Scoping Functions apply vs. with, let, also, and run

What do they do?

inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return
receiver.block()
}
class Person {
var name: String? = null
var age
: Int? = null
}

val person: Person = getPerson()
print(person.name)
print(person.age)
val person: Person = getPerson()
with(person) {
print(name)
print(age)
}

Differences between apply, with, let, also, and run

inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return
receiver.block()
}
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
  1. The receiver argument is provided as an explicit parameter T in the case of with(), whereas it is provided as an implicit receiver T in the case of also().
  2. The block argument is defined as a function that has an implicit receiver T in the case of with(), whereas it has an explicit argument T in the case of also().
  3. The with() function returns what is returned by executing its block argument, whereas the also() function returns the same object that was provided as its receiver.
val person: Person = getPerson().also {
print(it.name)
print(it.age)
}
  • explicit receiver parameter vs. implicit receiver
  • provided to the block argument as an explicit parameter vs. an implicit receiver
  • returning the receiver vs. returning what the block returns
inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return
receiver.block()
}
inline fun <T> T.also(block: (T) -> Unit): T {
block(this)
return this
}
inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
inline fun <T, R> T.run(block: T.() -> R): R {
return
block()
}

When to use apply, with, let, also, or run

Conventions for using apply

val peter = Person().apply {
// only access properties in apply block!
name = "Peter"
age
= 18
}
val clark = Person()
clark.name = "Clark"
clark.age = 18

Conventions for using also

class Book(author: Person) {
val author = author.also {
requireNotNull(it.age)
print(it.name)
}
}
class Book(val author: Person) {
init {
requireNotNull(author.age)
print(author.name)
}
}

Conventions for using let

  • execute code if a given value is not null
  • convert a nullable object to another nullable object
  • limit the scope of a single local variable
getNullablePerson()?.let {
// only executed when not-null
promote(it)
}
val driversLicence: Licence? = getNullablePerson()?.let {
// convert nullable person to nullable driversLicence
licenceService.getDriversLicence(it)
}
val person: Person = getPerson()
getPersonDao().let { dao ->
// scope of dao variable is limited to this block
dao.insert(person)
}
val person: Person? = getPromotablePerson()
if (person != null) {
promote(person)
}
val driver: Person? = getDriver()
val driversLicence: Licence? = if (driver == null) null else
licenceService.getDriversLicence(it)
val person: Person = getPerson()
val personDao: PersonDao = getPersonDao()
personDao.insert(person)

Conventions for using with

val person: Person = getPerson()
with(person) {
print(name)
print(age)
}
val person: Person = getPerson()
print(person.name)
print(person.age)

Conventions for using run

val inserted: Boolean = run {
val person: Person = getPerson()
val personDao: PersonDao = getPersonDao()
personDao.insert(person)
}
fun printAge(person: Person) = person.run {
print(age)
}
val person: Person = getPerson()
val personDao: PersonDao = getPersonDao()
val inserted: Boolean = personDao.insert(person)
fun printAge(person: Person) = {
print(person.age)
}

Combining Multiple Scoping Functions

private fun insert(user: User) = SqlBuilder().apply {
append("INSERT INTO user (email, name, age) VALUES ")
append("(?", user.email)
append(",?", user.name)
append(",?)", user.age)
}.also {
print("Executing SQL update: $it.")
}.run {
jdbc
.update(this) > 0
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store