๐ŸŽ“ A1Learner
๐Ÿ”
0 of 37 lessons completed

Kotlin Safe Call Chains

A safe call chain follows links that may hold null without crashing. One null link makes the whole chain give null.

Two safe calls in one chain

The chain reads the address and then the city. A null holder makes the whole chain give null.

data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
    val person: Person? = Person("Ana", Address("Oslo"))
    println(person?.address?.city)
    val missing: Person? = null
    println(missing?.address?.city)
}

A chain that stops in the middle

The address link holds null here. The rest of the chain never runs, and the result is null.

data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
    val person = Person("Ana", null)
    println(person.address?.city?.length)
    println(person.address?.city?.length ?: -1)
}

A let block at the end of a chain

The let block runs for the chain with a real city. The other chain gives null, so its let block stays silent.

data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
    val person: Person? = Person("Ana", Address("Oslo"))
    person?.address?.city?.let { println("City $it") }
    val missing: Person? = Person("Bo", null)
    missing?.address?.city?.let { println("City $it") }
    println("done")
}

A chain with an Elvis fallback

The Elvis operator gives a fallback word when the chain gives null. A real city passes through unchanged.

data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
    val person: Person? = null
    println(person?.address?.city ?: "unknown city")
    val other: Person? = Person("Ana", Address("Oslo"))
    println(other?.address?.city ?: "unknown city")
}

Example

data class Address(val city: String?)
data class Person(val name: String, val address: Address?)
fun main() {
    val people = listOf(Person("Ana", Address("Oslo")), Person("Bo", null), Person("Cy", Address(null)))
    for (person in people) {
        println(person.address?.city?.length ?: 0)
    }
    val first: Person? = people.firstOrNull()
    first?.address?.city?.let { println(it.uppercase()) }
}

Key points

  • The safe call operator ?. reads a property only when the value before it is not null.
  • Two or more safe calls can link together in one expression.
  • The chain gives null as soon as one link holds null.
  • Later links in a stopped chain never run.
  • An Elvis fallback can stand in for the null result of a chain.
  • A let block at the end of a chain runs only when the chain gives a real value.

In this example, the loop prints the city length for the first holder and 0 for the other two. Both other chains hit a null link, so the Elvis fallback gives 0 each time. The final chain reaches a real city, so the let block prints the city in uppercase.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Kotlin Playground

Exercise

A holder holds null for its address link. What does holder.address?.city?.length give?