Inside an extension function declared on String?, what is the type of `this`, and how do you safely call String members on it?
answer
- this is String? inside the body
- Guard + smart-cast to non-null
- orEmpty = this ?: ""
- || short-circuits and smart-casts
- this is always a stable smart-cast target
basics
~20 sInside the body, this is nullable (String?). To use String members you must first check it is not null; after that check the compiler treats this as non-null, so you can call methods like length.
solid answer
~40 sWhen the receiver type is `String?`, `this` has type `String?` inside the body — it is NOT automatically non-null. You cannot call non-null members like `this.length` directly. You make it usable by narrowing nullability: a guard such as `if (this == null) return ...` smart-casts `this` to `String` afterwards, or use `this?.length`, `this ?: default`, or `this?.let { ... }`. Smart-cast works on `this` exactly as it does on any nullable local. Note smart-cast requires a stable value; `this` is always stable, so it works reliably. The library leans on this: `orEmpty()` is `this ?: ""`, and `isNullOrEmpty()` is `this == null || this.length == 0` — the `||` short-circuit smart-casts `this` to non-null on the right-hand side.
code
kotlin · 8 linesfun String?.wordCount(): Int {
if (this == null) return 0
return this.trim().split(Regex("\\s+"))
.filter { it.isNotEmpty() }.size // this: String
}
println((null as String?).wordCount()) // 0
println("a b c".wordCount()) // 3go deeper
Knows you must null-check this before using String members.
States this is String?, uses guard/Elvis/safe-call, and knows smart-cast narrows it.
Explains short-circuit smart-cast and why this is a stable smart-cast target.
Reasons about readability/contract clarity of handling null inside vs. requiring non-null at the API boundary.
## The type of `this` Declare `fun String?.foo()`. The receiver type is `String?`, so **inside the body `this` is of type `String?`**. It is nullable. The compiler will reject `this.length` because you cannot dereference a possibly-null value. ## Making `this` usable You narrow the nullability with the same tools you'd use on any nullable variable: - **Early return / guard** — `if (this == null) return X`. After this line, `this` is **smart-cast** to the non-null `String`: ```kotlin fun String?.firstCharOr(d: Char): Char { if (this == null || isEmpty()) return d return this[0] // this is String here } ``` - **Safe call** — `this?.length` yields `Int?`. - **Elvis** — `this ?: ""` (this is exactly how `orEmpty()` is written). - **Scope function** — `this?.let { it.length }`. ## Smart-cast and short-circuiting **Smart-cast** is the compiler automatically treating a value as a more specific (here, non-null) type after a check proves it. Because `this` is a **stable** identifier, smart-cast on `this` is reliable. Boolean operators short-circuit and smart-cast within the same expression: ```kotlin public inline fun CharSequence?.isNullOrEmpty(): Boolean = this == null || this.length == 0 // RHS: this smart-cast to CharSequence ``` After `this == null ||`, the right side only runs when `this != null`, so `this.length` is allowed. ## Calling other nullable-receiver extensions From inside, you can still call *other* nullable-receiver extensions on `this` without a check (e.g. `isNullOrEmpty()`), because those declare a `String?` receiver too. You only need the null check before calling **non-null** members or extensions. ## Gotcha Don't assume the receiver is non-null just because callers "usually" pass non-null. The contract is `String?`; design the body to handle `null` explicitly, or you'll get a compile error (not an NPE) the moment you touch a non-null member.
- Does smart-cast on this ever fail to apply?this is always stable, so the null-narrowing smart-cast applies reliably; it can still be blocked if you reassign through an unstable path, but you cannot reassign this itself.
- How is orEmpty() implemented for String?public fun String?.orEmpty(): String = this ?: "" — Elvis returns an empty string when this is null.
saying these in an interview costs you the question
- Saying this is non-null inside a String? extension
- Calling this.length without a null narrowing
- Confusing smart-cast with an unchecked cast (as)
- Thinking you must use !! to reach members