An unchecked cast converts a value to a generic type even though its type argument cannot be verified at runtime. Kotlin can confirm a value’s base type, such as List, but generic arguments such as Int are erased. The compiler therefore allows casts like `as List<Int>` or `as? List<Int>` with an unchecked-cast warning. A successful cast means only that the value has the requested base type; it does not prove that every element has the requested generic type. section 11.2.1
A cast that succeeds too early
`fun printSum(c: Collection<*>) { val ints = c as? List<Int> ?: throw IllegalArgumentException("List is expected"); println(ints.sum()) }` A list of integers prints its sum. A set of integers fails immediately because it is not a List. But a `List<String>` passes the cast: its runtime type is still List. The later call to `sum()` attempts to use strings as numbers and throws `ClassCastException`. Use `as?` to handle a wrong base type, not to validate generic arguments. section 11.2.1
Prefer checks that express only the information actually available. `is List<*>` checks for a list with unknown element type and avoids claiming that its elements are Int values. Kotlin can permit a check such as `is List<Int>` when the element type is already known statically—for example, when a parameter is `Collection<Int>`—because the check then distinguishes collection implementations rather than discovering erased element types. section 11.2.1
When an unchecked cast is unavoidable, make the unsafe boundary small:
- Do not treat a cast from `FieldValidator<*>` to `FieldValidator<String>` as proof that the validator accepts strings; a mismatched validator fails only when validation receives the wrong value. section 11.3.6
- Avoid explicit casts as a general way to use star-projected values. A star projection deliberately prevents supplying a value whose type is unknown. section 11.3.6
- Encapsulate the cast behind a generic API that controls registration and lookup. Keep the warning, and any `@Suppress("UNCHECKED_CAST")`, inside that implementation rather than exposing it to callers. section 11.3.6
- Make the enclosing API type-safe: register `FieldValidator<T>` with its matching `KClass<T>` and return the same `FieldValidator<T>` for a lookup. section 11.3.6
Localizing a validator-registry cast
A registry can store heterogeneous entries as `MutableMap<KClass<*>, FieldValidator<*>>`, then expose generic `registerValidator` and `get` operations. Its lookup performs the unchecked cast internally after the registry has controlled which validator was associated with each class. Callers receive a validator whose input type is checked by the compiler: requesting the String validator and passing `42` is rejected before runtime. section 11.3.6
Listing 11.5 Using a type cast with a generic type
fun printSum(c: Collection<*>) {
val intList = c as? List<Int> #1
?: throw IllegalArgumentException("List is expected")
println(intList.sum())
}
Inspect the compact `printSum` example to separate the base-type test performed by `as?` from the erased element-type claim that triggers the warning. section 11.2.1
Unchecked casts shift responsibility from Kotlin’s type system to the code that performs the cast. They are sometimes useful at a controlled interoperability or storage boundary, but they are error-prone when scattered through application logic. Prefer star projections for unknown generic arguments and a narrow, audited generic wrapper when heterogeneous values must be stored together. section 11.2.1 section 11.3.6

