Let a checked type narrow the value
An is check tests runtime type. Where the compiler can prove the value is stable, it smart-casts the value inside the successful branch, removing the need for an explicit cast.
fun describe(value: Any?): String = when (value) {
null -> "Missing"
is String -> "Text: ${value.length} characters"
is Int -> "Integer: ${value + 1} after increment"
else -> "Other value"
}
A mutable property with a custom getter may change between accesses, so the compiler cannot always smart-cast it. Read it once into a local val and check that snapshot when appropriate. This stabilizes that read; it does not make an entire mutable object thread-safe.
Use is List<*> to recognize a list at runtime, but do not assume that a generic element type such as String can be checked directly after JVM type erasure. Validate elements separately.
Exercise
Implement a function accepting Any? and returning a string's trimmed length or null for other types. Test a string, integer, null, and an empty string.
Check: explain why a compiler error on a smart cast can reveal unstable state rather than a missing explicit cast.