SyntaxStudy
Sign Up
Kotlin Safe Casts and Smart Casts
Kotlin Beginner 1 min read

Safe Casts and Smart Casts

Kotlin's is operator checks type at runtime and simultaneously narrows the type in the enclosing scope — this is called a smart cast. After a successful is check inside an if branch or when clause, the compiler knows the exact type and allows you to use type-specific members without an explicit cast. The safe cast operator as? attempts a cast and returns null instead of throwing a ClassCastException if the object is not the expected type. This pairs naturally with the Elvis operator to provide a fallback value. Unsafe casts using as behave like Java casts and throw an exception on failure. Smart casts work not just with is but also with null checks: once the compiler can prove that a nullable variable cannot be null at a particular point — because of a preceding null check or early return — it treats the variable as non-nullable from that point on.
Example
open class Animal(val name: String)
class Dog(name: String) : Animal(name) { fun bark() = println("$name: Woof!") }
class Cat(name: String) : Animal(name) { fun purr() = println("$name: Purrr...") }

fun interact(animal: Animal) {
    // Smart cast after is check
    when (animal) {
        is Dog -> animal.bark()   // animal is Dog here
        is Cat -> animal.purr()   // animal is Cat here
        else   -> println("${animal.name} just stares at you")
    }
}

fun parseNumber(value: Any): Double? {
    // Safe cast — returns null on failure
    val str = value as? String ?: return (value as? Number)?.toDouble()
    return str.toDoubleOrNull()
}

fun nullSmartCast(text: String?) {
    // Early return eliminates nullable in the rest of the function
    if (text == null) return
    println(text.uppercase())   // text is String here, not String?
}

fun main() {
    val animals: List<Animal> = listOf(Dog("Rex"), Cat("Whiskers"), Animal("Bird"))
    animals.forEach(::interact)

    println(parseNumber("3.14"))   // 3.14
    println(parseNumber(42))       // 42.0
    println(parseNumber(true))     // null

    nullSmartCast("hello")   // HELLO
    nullSmartCast(null)      // (nothing printed)
}