skip to content

Safe Call Operator ?.

?. short-circuits to null instead of dereferencing, so a?.b has a nullable type and long chains stay safe. The natural follow-up is combining it with let or also to run a block only when the value is actually there.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What does the safe-call operator ?. do in Kotlin, and what is the type of a?.length when a is a String??

level: juniorimportance: must knowfreq 90%

answer

  1. null receiver -> whole expression is null
  2. result type becomes nullable (T -> T?)
  3. short-circuits: member never evaluated when null
  4. default safe alternative to !!
  5. receiver evaluated once

basics

~20 s

?. only calls the method or reads the property if the value on the left is not null. If it is null, the whole expression is null instead of crashing. So a?.length gives an Int? (a number or null).

solid answer

~30 s

The ?. safe-call operator guards a member access. For a?.length, Kotlin first checks whether a is null. If a is null it short-circuits and yields null without evaluating .length; if a is non-null it accesses .length normally. Because either outcome is possible, the result type is nullable: a?.length is Int? even though String.length is a non-null Int. This is how you read members of a nullable receiver without a NullPointerException. Contrast with plain a.length (won't compile on a nullable a) and a!!.length (throws NPE if null). ?. is the safe, idiomatic default for nullable receivers.

code

kotlin · 4 lines
kotlin
val a: String? = null
val len: Int? = a?.length  // null, no NPE
val b: String? = "hi"
val len2: Int? = b?.length // 2

go deeper

for a junior

Knows ?. avoids NPE and the result is nullable.

for a middle

Explains short-circuit semantics and that receiver is evaluated once.

for a senior

Frames ?. against !!/?: in the broader null-safety model and type propagation.

for a principal

Discusses how null-safety types and ?. shape API design and reduce defensive null checks across a codebase.

## The safe-call operator `?.` In Kotlin the type system distinguishes **non-nullable** types (`String`) from **nullable** types (`String?`, the `?` suffix). You cannot dereference a nullable value directly — `a.length` where `a: String?` is a compile error. The **safe-call operator** `?.` lets you access a member of a possibly-null receiver safely. ### Semantics `a?.length` is equivalent to: *if `a` is `null`, the result is `null`; otherwise the result is `a.length`*. The receiver `a` is evaluated once. When it is null, `.length` is **never** evaluated (short-circuit). ```kotlin val a: String? = null val n: Int? = a?.length // n == null, no exception val b: String? = "hi" val m: Int? = b?.length // m == 2 ``` ### Result type is nullable Even though `String.length` returns a non-null `Int`, `b?.length` has type `Int?`: the safe call introduces the possibility of `null` into the result. Generally, for `receiver?.member` of declared type `T`, the expression type is `T?`. This propagates: you often pair it with the Elvis operator (`?:`) or `?.let` to collapse back to a non-null value, but those are separate operators. ### Contrast with neighbours - `a.length` — does **not compile** when `a: String?`. - `a!!.length` — the not-null assertion; throws `NullPointerException` if `a` is null. - `a?.length` — yields `null` silently if `a` is null. Use `?.` as the default safe way to touch members of a nullable receiver.

  • Why is a?.length nullable even though String.length is non-null?
    Because the safe call can itself produce null (when the receiver is null), so the overall type must admit null: Int?.
  • What happens if you write a.length instead?
    It fails to compile, because a is of type String? and Kotlin forbids dereferencing a nullable type directly.

Like asking 'if the door is there, knock' — no door, no knock, and you don't trip over a missing door.

saying these in an interview costs you the question

  • Saying a?.length returns a non-null Int
  • Claiming ?. throws an exception when the receiver is null
  • Confusing ?. (safe call) with !! (not-null assertion)
  • Thinking a.length compiles on a nullable receiver
  • Saying the member is still evaluated when the receiver is null

context

open as a page

How does chaining safe calls like a?.b?.c work, and what is the result type? What happens if b is null in the middle?

level: middleimportance: must knowfreq 80%

basics

~20 s

You can stack ?. through a chain. If any link is null, the whole chain stops and becomes null. The final result is nullable. So a?.b?.c is null if a, a.b, or a.b.c is null.

open as a page

How do you combine ?. with let and also (i.e. ?.let / ?.also) to run a block only when a value is non-null, and how do they differ?

level: middleimportance: should knowfreq 75%

basics

~20 s

Write value?.let { ... } to run the block only when value is not null. Inside, the value is non-null. ?.let returns the block's result; ?.also returns the original value and is used for side effects like logging.

open as a page

What is the result of a safe call on an extension function or a function returning Unit, and how does ?. interact with platform (Java) types?

level: seniorimportance: should knowfreq 45%

basics

~20 s

A safe call on a function that returns Unit gives Unit? — it's null when the receiver was null. ?. works on extension functions too. With Java values (platform types), the compiler doesn't force ?., so you must add it yourself to stay safe.

open as a page

How does the Kotlin compiler lower a?.b?.c to JVM bytecode/Java, and what are the receiver-evaluation and short-circuit guarantees a senior should rely on?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Under the hood, a?.b becomes a null check: evaluate the receiver once, if it's null give null, otherwise read the member. Chained calls become nested checks that stop at the first null. The receiver is only computed one time.

open as a page