0Pricing
Kotlin Academy · Lesson

Smart Casts

Auto-cast after checks.

Smart Casts is a free Kotlin Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Are Smart Casts

After you check a value's type, Kotlin remembers that fact. Inside the checked block, it treats the value as the narrowed type automatically.

This feature is called a smart cast, and it removes manual casting.

Smart Cast After is

Once an is check passes, you can use the value as that type without writing a cast.

The compiler inserts it for you.

fun describe(x: Any) {
    if (x is String) {
        println(x.length) // x is smart-cast to String
    }
}

fun main() {
    describe("hello")
}

Smart Cast After Null Check

Smart casts also work for nullability. After confirming a value is not null, it is treated as non-null.

fun length(text: String?): Int {
    if (text != null) {
        return text.length // smart-cast to non-null String
    }
    return 0
}

fun main() {
    println(length("abc"))
    println(length(null))
}

Smart Casts in when

Type checks inside when also enable smart casts in each branch.

This is the idiomatic way to handle multiple possible types.

fun area(shape: Any): Double = when (shape) {
    is Int -> shape.toDouble()
    is String -> shape.length.toDouble()
    else -> 0.0
}

fun main() {
    println(area(5))
    println(area("hello"))
}

Smart Cast with Early Return

If you return early when a value is null, the compiler knows it is non-null afterward.

The rest of the function uses the value safely.

fun process(text: String?) {
    if (text == null) return
    println(text.uppercase()) // smart-cast here
}

fun main() {
    process("data")
    process(null)
}

Smart Cast with Elvis Return

Combining Elvis with return also triggers a smart cast for the remaining code.

fun process(text: String?) {
    val safe = text ?: return
    println(safe.length) // safe is non-null
}

fun main() {
    process("hi")
    process(null)
}

Combined Conditions

Smart casts respect the logic of combined conditions using &&.

After the type check on the left, the right side already sees the narrowed type.

fun check(x: Any) {
    if (x is String && x.length > 3) {
        println("long string")
    } else {
        println("other")
    }
}

fun main() {
    check("hello")
    check(2)
}

When Smart Casts Fail

Smart casts need a guarantee the value will not change between the check and the use.

A mutable var that could change concurrently may not smart-cast. Prefer val for reliable smart casts.

fun main() {
    val text: String? = "stable"
    if (text != null) {
        println(text.length) // val smart-casts cleanly
    }
}

Local val Is Safest

Copying a value into a local val makes smart casts dependable.

This is a common pattern when working with nullable properties.

class Box(val content: String?)

fun main() {
    val box = Box("item")
    val c = box.content
    if (c != null) {
        println(c.uppercase())
    }
}

Smart Cast vs Explicit Cast

Smart casts replace most explicit as casts. They are safer because they only apply where the type is proven.

You will learn explicit is and as next.

fun main() {
    val x: Any = "text"
    if (x is String) {
        // no need for (x as String)
        println(x.reversed())
    }
}

Putting It Together

Smart casts let the compiler narrow types automatically:

  • After is checks → cast to that type
  • After null checks → cast to non-null
  • Work in if, when, and after early returns
  • Most reliable with val
fun render(x: Any): String {
    if (x is Int) return "number " + x
    if (x is String) return "text " + x.uppercase()
    return "unknown"
}

fun main() {
    println(render(7))
    println(render("go"))
}

Quick Check

Test your understanding of smart casts.

Recap

You learned about smart casts:

  • Type and null checks narrow the type automatically
  • They work in if, when, and after early returns
  • val gives the most reliable smart casts

Next you will study the is and as operators directly.

Frequently asked questions

Is the “Smart Casts” lesson free?

Yes — the full text of “Smart Casts” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “Smart Casts”?

Auto-cast after checks. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Smart Casts” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. when as Expression
  2. Smart Casts
  3. is and as Operators
  4. Exhaustive when
← Back to Kotlin Academy