Introduction
In many languages, checking a variable's type or nullability doesn't change how the compiler treats it afterward; you still need an explicit cast to use it as the narrower type. Kotlin removes this redundancy with smart casts: once the compiler proves, through a null-check or an is type-check, that a variable has a certain type within a given scope, it automatically treats the variable as that type for the rest of the scope. This is possible because Kotlin's compiler performs flow-sensitive analysis, tracking what is known about a variable at each point in the code.
Cricket analogy: Once an umpire confirms a delivery was a no-ball, the scorer doesn't need to re-check on every subsequent action within that phase, similar to how Kotlin's compiler, after an is or null check, automatically treats a variable as the narrower type for the rest of the scope.
Syntax
fun printLength(text: String?) {
if (text != null) {
// text is smart-cast to String (non-null) here
println(text.length)
}
}
fun describe(obj: Any) {
if (obj is String) {
// obj is smart-cast to String here
println(obj.uppercase())
}
}Explanation
A smart cast happens when the compiler can guarantee that a check performed earlier in the code still holds true at the point of use. After if (x != null), the compiler knows x cannot be null inside that branch, so it lets you call non-null-only methods on x directly, without ?. or !!. Similarly, after if (obj is String), the compiler knows obj is a String inside that branch, so it exposes String's members without an explicit as String cast. Smart casts also work with when expressions and with the && / || operators in a single condition. However, smart casts are not reliable for var properties that could be modified by another thread between the check and the use, nor for properties with custom getters, since the compiler cannot guarantee the value hasn't changed; in those cases you still need an explicit cast or a local copy of the value.
Cricket analogy: After the umpire confirms 'not out' (x != null), the scorer can record the run directly without a second check, just as Kotlin lets you call methods on x without ?. inside that branch; but if a runner (a var open to change) could be substituted mid-over, you can't trust the earlier check.
Example
fun describe(input: Any?) {
when {
input == null -> println("input is null")
input is Int -> println("Int doubled: ${input * 2}")
input is String -> println("String length: ${input.length}")
else -> println("Unknown type")
}
}
fun main() {
describe(21)
describe("Kotlin")
describe(null)
}Output
Int doubled: 42
String length: 6
input is nullKey Takeaways
- Smart casts let the compiler treat a variable as a narrower or non-null type after a check, without an explicit cast.
- They work after null-checks (if (x != null)) and type-checks (if (x is String)).
- Kotlin's compiler tracks flow-sensitive information to know when a smart cast is safe.
- Smart casts also apply inside when expressions and combined boolean conditions.
- Smart casts are unreliable for mutable var properties that another thread could modify, and for properties with custom getters.
Practice what you learned
1. What makes Kotlin able to perform a smart cast after if (x != null)?
2. After if (obj is String) { ... }, what can you do with obj inside the block?
3. In which scenario is a smart cast NOT guaranteed to work?
4. Why might a smart cast fail on a property with a custom getter?
Was this page helpful?
You May Also Like
Null Safety in Kotlin
Kotlin's type system distinguishes nullable from non-nullable types at compile time, eliminating most NullPointerExceptions before code ever runs.
when Expression in Kotlin
Explore Kotlin's when expression, a powerful and flexible replacement for Java's switch statement.
Type Conversion in Kotlin
Understand why Kotlin requires explicit conversion between numeric types and how to use functions like toInt() and toDouble().
Sealed Classes in Kotlin
Sealed classes restrict a class hierarchy to a known, closed set of subclasses, enabling exhaustive when checks.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics