liveBook · Manning

Data conversion

As explained in Kotlin in Action, 2E

Data conversion is the transformation of a value or data from one type, format, or representation to another, explicitly or implicitly.

In Kotlin, data conversion commonly appears as interpreting a value as another type. An explicit cast uses `as`; a smart cast combines an `is` check with compiler-provided conversion, reducing redundant code while preserving safety. section 2.3.6

Prefer a smart cast after a type check

interface Expr class Num(val value: Int) : Expr fun eval(e: Expr): Int { if (e is Num) { return e.value } throw IllegalArgumentException("Unknown expression") } The `is Num` check lets `e.value` work without writing `e as Num`. The compiler permits this only when the value cannot change after the check, such as a stable `val` property without a custom accessor. section 2.3.6

Choose the conversion form according to the information available at runtime:

  • Use `is` when branching on a known type; Kotlin can then smart-cast the value inside the branch. section 2.3.6
  • Use `as` for an explicit cast when the expected type is certain; use `as?` when a failed conversion should produce `null`. section 2.3.6 section 11.2.1
  • Do not rely on runtime checks for generic type arguments: type erasure prevents distinguishing `List<String>` from `List<Int>`. section 11.2.1
  • Use `List<*>` to check that a value is some kind of list without claiming its element type. section 11.2.1

A safe cast still needs validation

fun printSum(c: Collection<*>) { val intList = c as? List<Int> ?: throw IllegalArgumentException("List is expected") println(intList.sum()) } This accepts `listOf(1, 2, 3)` but rejects a set. A list containing strings can still produce a `ClassCastException`, because erased generic information cannot fully verify the element type at runtime. section 11.2.1

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
}

Inspect the complete expression evaluator to see explicit casting replaced by smart-cast access in a runnable example. section 2.3.6

How Kotlin in Action, 2E covers it

How deep it goes
Explains explicit casts, smart-cast stability, generic erasure, star projections, and runtime failure cases.
Examples
Demonstrates expression evaluation, numeric and string lists, star projections, safe casts, sets, and runtime cast exceptions.
What it assumes
Assumes basic Kotlin types and classes while introducing type checks, explicit casts, smart casts, and generic runtime constraints.
What you can do after
Apply Kotlin type checks and casts while avoiding redundant casts and recognizing erased generic type limitations.
How it connects
Connects data conversion with type checks, smart casts, generics, type erasure, nullability, and exception handling.

Also explained in

Compare how 21 books explain data conversion →

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.