Smart cast in Kotlin: why a variable could have changed and how to fix it in 2025

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

"But I just checked!" — the familiar pain of every Kotlin developer

\n

You're writing in Kotlin, enjoying its conciseness and safety, when suddenly — a red squiggly line. The compiler outputs: Smart cast to 'Type' is impossible, because 'variable' is a mutable property that could have been changed by this time. Sound familiar? If you've ever encountered this error, you're not alone. This question is one of the most popular on Stack Overflow, and for good reason: it raises a fundamental topic — how Kotlin protects us from ourselves.

\n

In this article, we will not only break down why the error occurs, but also show how to elegantly avoid it in 2025. You'll learn what a smart cast is, why Kotlin doesn't trust mutable properties, and what best practices will help you write clean, safe code without unnecessary "crutches". Let's go!

\n\n

What is a smart cast and why is it "smart"?

\n

One of Kotlin's strong points is smart casting. This is when the compiler itself understands that after checking a variable's type, it can be used as that type without an explicit cast. For example:

\n
fun printLength(obj: Any) {\n    if (obj is String) {\n        // Smart cast: obj automatically became String\n        println(obj.length)\n    }\n}
\n

Nice, right? The compiler sees: "Aha, we checked that obj is a String, so inside the if block it's definitely a string, we can call length." That's smart casting.

\n

But there's a nuance: this trick only works if the compiler can guarantee that the variable will not change between the check and the usage. But if the variable is a var (mutable), there are no guarantees. And that's where the fun begins.

\n\n

The root of the evil: mutable property

\n

Let's look at a typical example that causes the error:

\n
class UserRepository {\n    var currentUser: User? = null\n\n    fun printUserName() {\n        if (currentUser != null) {\n            // Error! Smart cast to 'User' is impossible\n            // because currentUser is a var, and could have changed\n            println(currentUser.name)\n        }\n    }\n}
\n

What's the matter? We just checked that currentUser is not null! The compiler answers: "Buddy, you're using a var. This means that between the check and the println call, another thread (or even this same code elsewhere) could have changed currentUser back to null. I can't take the risk — what if there's an NPE?"

\n

And this is correct! Kotlin is a language with a null-safe philosophy. It doesn't let you shoot yourself in the foot. Even if you're sure no one will change the property, the compiler plays it safe. This is better than catching a NullPointerException at runtime.

\n\n

How to fix it? 5 proven ways (2025 edition)

\n

The good news: there are several solutions, and they are all simple. Choose the one that best fits your coding style and situation.

\n\n

1. Local immutable copy (the most reliable)

\n

The most straightforward way is to save the value into a val (a local immutable variable). The compiler immediately sees that the local val won't be changed by anyone, and smart casting works:

\n
fun printUserName() {\n    val user = currentUser\n    if (user != null) {\n        // Smart cast works! user is a local val\n        println(user.name)\n    }\n}
\n

This technique is the gold standard. It's simple, readable, and doesn't require any additional libraries. In 2025, this is still the most recommended way.

\n\n

2. The let function (elegant way)

\n

The let function is a great tool for working with nullable values. It executes a block of code only if the object is not null, and inside the block the object is accessible as it (or you can give it a name):

Blogs

Book Recommendations