# Safe Calls & the Elvis Operator

Kotlin provides convenient operations for handling nullability.

Nullable types come with numerous restrictions. You can’t simply dereference an identifier of a nullable type:

// SafeCallsAndElvis/DereferenceNull.kt

fun main() {
  val s: String? = null
  // Doesn't compile:
  // s.length        // [1]
}

Uncommenting [1] produces a compile-time error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?.

A safe call replaces the dot (.) in a regular call with a question mark and a dot (?.), without intervening space. Safe calls access members of a nullable in a way that ensures no exceptions are thrown. They only perform an operation when the receiver is not null:

// SafeCallsAndElvis/SafeOperation.kt
package safecalls
import atomictest.*

fun String.echo() {
  trace(toUpperCase())
  trace(this)
  trace(toLowerCase())
}

fun main() {
  val s1: String? = "Howdy!"
  s1?.echo()                  // [1]
  val s2: String? = null
  s2?.echo()                  // [2]
  trace eq """
    HOWDY!
    Howdy!
    howdy!
  """
}

Line [1] calls echo() and produces results in the trace, while line [2] does nothing because the receiver s2 is null.

Safe calls are a clean way to capture results:

// SafeCallsAndElvis/SafeCall.kt
package safecalls
import atomictest.eq

fun checkLength(s: String?, expected: Int?) {
  val length1 =
    if (s != null) s.length else null  // [1]
  val length2 = s?.length              // [2]
  length1 eq expected
  length2 eq expected
}

fun main() {
  checkLength("abc", 3)
  checkLength(null, null)
}

Line [2] achieves the same effect as line [1]. If the receiver is not null it performs a normal access (s.length). If the receiver is null it doesn’t perform the s.length call (which would cause an exception), but produces null for the expression.

What if you need something more than the null produced by ?.? The Elvis operator provides an alternative. This operator is a question mark followed by a colon (?:), with no intervening space. It is named for an emoticon of the musician Elvis Presley, and is also a play on the words “else-if” (which sounds vaguely like “Elvis”).

A number of programming languages provide a null coalescing operator that performs the same action as Kotlin’s Elvis operator.

If the expression on the left of ?: is not null, that expression becomes the result. If the left-hand expression is null, then the expression on the right of the ?: becomes the result:

// SafeCallsAndElvis/ElvisOperator.kt
import atomictest.eq

fun main() {
  val s1: String? = "abc"
  (s1 ?: "---") eq "abc"

  val s2: String? = null
  (s2 ?: "---") eq "---"
}

s1 is not null, so the Elvis operator produces "abc" as the result. Because s2 is null, the Elvis operator produces the alternate result of "---".

The Elvis operator is typically used after a safe call, to produce a meaningful value instead of the default null, as you see in [2]:

// SafeCallsAndElvis/ElvisCall.kt
package safecalls
import atomictest.eq

fun checkLength(s: String?, expected: Int) {
  val length1 =
    if (s != null) s.length else 0    // [1]
  val length2 = s?.length ?: 0        // [2]
  length1 eq expected
  length2 eq expected
}

fun main() {
  checkLength("abc", 3)
  checkLength(null, 0)
}

This checkLength() function is quite similar to the one in SafeCall.kt above. The expected parameter type is now non-nullable. [1] and [2] produce zero instead of null.

Safe calls allow you to write chained calls concisely, when some elements in the chain might be null and you’re only interested in the final result:

// SafeCallsAndElvis/ChainedCalls.kt
package safecalls
import atomictest.eq

class Person(
  val name: String,
  var friend: Person? = null
)

fun main() {
  val alice = Person("Alice")
  alice.friend?.friend?.name eq null   // [1]

  val bob = Person("Bob")
  val charlie = Person("Charlie", bob)
  bob.friend = charlie
  bob.friend?.friend?.name eq "Bob"    // [2]

  (alice.friend?.friend?.name
    ?: "Unknown") eq "Unknown"         // [3]
}

When you chain access to several members using safe calls, the result is null if any intermediate expressions are null.

  • [1] The property alice.friend is null, so the rest of the calls return null.
  • [2] All intermediate calls produce meaningful values.
  • [3] An Elvis operator after the chain of safe calls provides an alternate value if any intermediate element is null.

Exercises and solutions can be found at www.AtomicKotlin.com.