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?
answer
- Unit-returning call -> Unit? (null if receiver null)
- ?. dispatches to extension functions
- extension on nullable receiver can use plain .
- Java platform type String! relaxes null checks
- treat unannotated Java returns as nullable, add ?.
basics
~20 sA 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.
solid answer
~40 s?. applies uniformly: receiver?.member where the member returns T yields T?. Even Unit-returning calls become Unit? — null if the receiver was null, Unit otherwise — so you can branch on the result. ?. also dispatches to extension functions; if the extension is declared on a non-null type, the safe call only invokes it when the receiver is non-null. The subtle case is platform types from Java (e.g. T! shown in IDEs): Java has no nullability info, so the compiler permits both x.foo() and x?.foo() and won't error if x is null — a plain call can still NPE at runtime. Best practice: treat unannotated Java returns as nullable and use ?. (or assert non-null explicitly). Annotations like @Nullable/@NotNull or @Nonnull improve this by giving the Kotlin compiler real nullability.
code
kotlin · 3 linesval ran: Unit? = list?.clear() // null if list was null
val out: String? = nullable?.shout() // extension fn via safe call
val len = javaObj.name?.length // guard platform type with ?.go deeper
Knows ?. avoids NPE; may not know about Unit? or platform types.
Understands ?. returns a nullable result and works on extensions.
Explains Unit?, extension dispatch, and the platform-type relaxation with its NPE risk.
Sets boundary conventions (annotate Java, enforce ?. at interop edges, JSpecify) to keep null safety intact across the codebase.
## Safe calls on Unit, extensions, and platform types ### Safe call always yields a nullable type For any `receiver?.member` where the member's type is `T`, the expression type is `T?`. This holds even when `T` is `Unit`: ```kotlin val list: MutableList<Int>? = maybeList() val result: Unit? = list?.clear() // Unit if cleared, null if list was null if (list?.clear() != null) { /* clear actually ran */ } ``` This `Unit?` trick lets you detect whether a void-like call executed. ### `?.` works with extension functions Safe call dispatches to **extension functions** just like members: ```kotlin fun String.shout() = uppercase() + "!" val s: String? = maybeText() val out: String? = s?.shout() // runs only if s != null ``` A subtlety: an extension can be declared on a **nullable** receiver (`fun String?.orEmpty()`); calling it with a plain `.` is allowed and the function itself handles null internally. But for an extension on a **non-null** type, `?.` ensures it only runs when the receiver is non-null. ### Platform types (Java interop) When Kotlin calls Java code that lacks nullability annotations, the result has a **platform type**, displayed as `String!`. The compiler **relaxes** null checks for these: it lets you write **either** `x.foo()` **or** `x?.foo()` and won't force the safe call. The danger: a plain call on a value that is actually null throws `NullPointerException` at runtime. ```kotlin // Java: String getName() { return null; } val name = javaObj.name // platform type String! val len1 = name.length // compiles, NPE at runtime if null val len2 = name?.length // safe: Int? ``` **Guidance:** treat unannotated Java returns as nullable and use `?.` (or `requireNotNull`). Java nullability annotations (`@Nullable`, `@NotNull`, JSpecify `@Nullable`) propagate real nullability so the Kotlin compiler enforces correctness and platform types disappear. ### Why this matters The value of `?.` is that the **type system** carries nullability. Platform types are the one hole where that guarantee is loosened, so disciplined use of `?.` at the Java boundary preserves null safety.
- Why does the compiler not force ?. on a Java return value?Unannotated Java types are platform types with unknown nullability, so Kotlin relaxes checks and trusts the developer; a plain call can NPE at runtime.
- How can you make Java nullability enforced in Kotlin?Annotate the Java code with @Nullable/@NotNull (or JSpecify), which the Kotlin compiler reads to assign proper nullable/non-null types.
saying these in an interview costs you the question
- Saying a safe call on a Unit function is a compile error
- Believing the compiler always forces ?. on Java return values
- Assuming platform types can never NPE
- Not knowing ?. works with extension functions
- Thinking Unit? is meaningless / cannot be branched on