liveBook · Manning

Type checking

As explained in Kotlin in Action, 2E

A type check is a Kotlin operation that tests whether a value has a specified runtime type.

Type checking tests whether a value has a particular runtime type. In Kotlin, use `is`: after a successful check, the compiler treats the value as that type in the checked branch. This smart cast avoids a separate explicit cast and helps prevent class-cast failures. section 2.3.6 section 1.4.3

Evaluate a typed expression

`if (e is Num) return e.value` can access `value` directly because `e` is smart-cast to `Num`. Likewise, after `e is Sum`, `e.left` and `e.right` are available for recursive evaluation. A smart cast requires a value that cannot have changed after the check; class properties must be `val` without custom accessors. section 2.3.6

Listing 2.18 Evaluating expressions with an if cascade
fun eval(e: Expr): Int {
    if (e is Num) {
        val n = e as Num                         #1
        return n.value
    }
    if (e is Sum) {
        return eval(e.right) + eval(e.left)      #2
    }
    throw IllegalArgumentException("Unknown expression")
}
 
fun main() {
    println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
    // 7
}

Compare an explicit `as Num` cast with the smart-cast access available after an `is Num` check, then follow the recursive `Sum` case. section 2.3.6

Generic type arguments are erased at runtime. A check such as `is List<String>` is therefore not generally allowed: Kotlin can determine that a value is a `List`, but not whether its elements are strings or integers. Use `is List<*>` to test the raw collection shape, or rely on a type argument already known by the function signature. section 11.2.1

Use checks with generic collections carefully:

  • Check `is List<*>` when only the collection kind matters; `*` represents unknown type arguments. section 11.2.1
  • Do not assume `as? List<Int>` verifies element types: a list of strings can pass the list cast and fail later when used as numbers. section 11.2.1
  • Branch on `List<Int>` and `Set<Int>` when `Collection<Int>` already establishes the element type. section 11.2.1

How Kotlin in Action, 2E covers it

How deep it goes
Explains smart casts and their stability constraint, then details runtime limits caused by generic type erasure.
Examples
Demonstrates recursive `Expr` evaluation, checking an `Any` value for `String`, and distinguishing lists from sets.
What you can do after
Apply `is` and smart casts for subtype handling while avoiding invalid assumptions about erased generic arguments.
How it connects
Connects type checking with smart casts, explicit casts, nullability, generics, star projections, and Java `instanceof`.

Also explained in

Compare how 5 books explain type checking →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.