Type checks and smart casts
is tests a type. When control flow proves the test, Kotlin often exposes the narrower type without an explicit cast.
fun render(value: Any): String = when (value) {
is String -> "Text length: ${value.length}"
is Int -> "Number doubled: ${value * 2}"
else -> "Unsupported"
}
Inside the first branch, value is known to be String; inside the second, it is Int.
Guard clauses
fun normalizedName(value: Any?): String {
if (value !is String) return "Unknown"
return value.trim()
}
After the early return, every remaining path proves that value is a String. Guard clauses also keep the happy path less indented.
Why a smart cast can fail
Kotlin smart-casts only when it is sure the value cannot change after the check. A mutable property might have one value during the check and another during the next read, so the compiler may refuse the smart cast.
class Profile(var nickname: String?)
fun length(profile: Profile): Int {
val nickname = profile.nickname // stable snapshot
return if (nickname != null) nickname.length else 0
}
The local val reads nickname once. Kotlin knows this local value cannot be reassigned, so the null check remains valid when length is called.
Explicit and safe casts
value as TypethrowsClassCastExceptionif wrong.value as? Typereturnsnullif wrong.
val routeId: String? = arguments["id"] as? String
Values from a Bundle, Intent, network response, database, reflection, or Java may not have the expected type. Safely cast and validate them when they enter your code. Then pass a clear Kotlin type through the application instead of passing Any? everywhere.
A smart cast is Kotlin automatically treating a value as a more specific type after a successful check. It works only when the compiler can prove the value will not change between the check and its use. For a mutable property, copy one read into a local val when that behavior is correct.
Interview check
Why does checking a mutable property not always smart-cast it?
Because reading the property again may return a different value. Copy it to a local val when you want to check and use the same captured value.