ProgrammingBackend Developer

What is smart casting in Kotlin? How does it work with conditions, when expressions, nullable types, custom getters, and properties? Provide examples and pitfalls.

Pass interviews with Hintsage AI assistant

Answer.

Smart casting is a mechanism where the Kotlin compiler automatically "downgrades" the type after checking for a certain type or null. This allows properties and methods of the cast type to be used without explicit conversion.

Example:

fun demo(x: Any) { if (x is String) { println(x.length) // x is automatically cast to String } }

Works with:

  • is / !is operators (e.g., in if or when)
  • Nullable variables (if (x != null))
  • when expressions

Does not work:

  • When a property has a custom getter (the compiler loses confidence that the value hasn't changed between the check and use)
  • For open/var properties of a class

Example with nullable:

val str: String? = getString() if (str != null) println(str.length) // smart cast

When it doesn't work:

val something: Any get() = fetch() if (something is String) { println(something.length) // Error: smart cast is not possible }

Trick Question.

Can you rely on smart cast for open or var properties of a class within methods?

No! Smart cast works only with local variables and val properties in final classes. For open (open) or var properties, the compiler is not sure if the value can change due to other threads or subclasses. Manual cast or a local variable is required for them.

open class Base { open var maybeString: Any? = "abc" fun check() { if (maybeString is String) { // println(maybeString.length) // Error: Smart cast is not possible val asString = maybeString as String println(asString.length) // Explicit cast } } }

Examples of real errors due to ignorance of the subtleties of the topic.


Story

In one project, open var properties were used for screen logic data models. The programmer relied on smart cast after checking if (model is SomeType), but during compilation had to manually cast types, which reduced readability and added code duplication due to a lack of knowledge of smart cast limitations on var/open.


Story

When retrieving data through a getter (e.g., via a delegate or validation), smart cast for the value did not work. The developer did not understand the reasons and spent several hours debugging until discovering that the compiler does not apply smart cast to such getters as they can return different values between calls.


Story

In a project, when processing nullable values through if (obj != null), smart cast worked inside the branch, but when the code was parallelized, NullPointerException appeared due to accesses outside the guarantee area. This demonstrated insufficient understanding of the local action of smart cast and the specifics of multithreading scenarios with nullable variables.