Choosing a Scope Function

Decision Guide

Do you need the object back (builder / chain)?
   yes -> refers to it as this?  apply   (configure)
          refers to it as it?    also    (log / validate)
   no  -> null check / transform with it?   let
          call many members, compute result? run  (or with(obj) for a non-null object)

takeIf and takeUnless

Example

takeIf returns the object if the condition is true, otherwise null. It pairs nicely with ?.let and ?:.

fun main() {
    val input = "  coupon50 "
    val code = input.trim().takeIf { it.length >= 6 }?.uppercase()
    println(code)

    val age = 15
    val canVote = age.takeUnless { it < 18 }?.let { "Eligible" } ?: "Not eligible"
    println(canVote)
}

Output

COUPON50
Not eligible

Do Not Overuse

Note: Nesting scope functions (a?.let { b.run { c.also { } } }) quickly becomes unreadable, and it/this become ambiguous. If a plain if or a local val is clearer, use that.

Exercise: Rewrite using apply and also: create a MutableList<String>, add "A" and "B", print its size, then return it.

Show answer
val list = mutableListOf<String>()
    .apply { add("A"); add("B") }
    .also { println("Size: ${it.size}") }