Smart Casts / as?
| Since: | Kotlin 1.0(2016) |
|---|
Kotlin's smart cast automatically applies a cast after a type check using is, eliminating the need for an explicit cast. Use as for an explicit cast, and as? for a safe cast that returns null on failure.
Syntax
fun describe(value: Any) {
if (value is String) {
println(value.length) // Treated as String type.
}
}
// Use as for an explicit cast (throws ClassCastException on failure).
val str: String = value as String
// Use as? for a safe cast (returns null on failure).
val str: String? = value as? String
// Smart cast in a when expression
when (value) {
is Int -> println(value * 2)
is String -> println(value.uppercase())
is List<*> -> println(value.size)
}
Syntax Reference
| Syntax | Description |
|---|---|
| value is Type | Checks the type. If true, smart cast is applied in the subsequent block. |
| value !is Type | Negated type check. |
| value as Type | Explicit cast. Throws a ClassCastException if the cast fails. |
| value as? Type | Safe cast. Returns null if the cast fails. |
| when (value) { is Type -> } | Uses smart cast inside a when expression. |
Sample Code
sample_smart_cast_as.kt
sealed class Shape
data class Circle(val radius: Double) : Shape()
data class Rectangle(val width: Double, val height: Double) : Shape()
data class Triangle(val base: Double, val height: Double) : Shape()
// Call methods on each type using smart cast.
fun area(shape: Shape): Double {
return when (shape) {
is Circle -> Math.PI * shape.radius * shape.radius
is Rectangle -> shape.width * shape.height
is Triangle -> 0.5 * shape.base * shape.height
}
}
fun printInfo(value: Any) {
// Smart cast is applied after each is check.
when (value) {
is Int -> println("Int: ${value * 2}")
is String -> println("String (${value.length} chars): ${value.uppercase()}")
is List<*> -> println("List (${value.size} items): $value")
is Boolean -> println("Boolean: $value")
else -> println("Unknown: $value")
}
}
fun main() {
// Basic smart cast usage
printInfo(42)
printInfo("Kotlin")
printInfo(listOf(1, 2, 3))
printInfo(true)
// Safe cast with as?
val obj: Any = "Hello"
val str: String? = obj as? String
val num: Int? = obj as? Int // Cannot cast String to Int, so null
println("str: $str") // str: Hello
println("num: $num") // num: null
// Combining as? with ?:
val length = (obj as? String)?.length ?: 0
println("length: $length") // length: 5
// Smart cast with a sealed class
val shapes = listOf(
Circle(5.0),
Rectangle(4.0, 3.0),
Triangle(6.0, 4.0)
)
shapes.forEach { shape ->
println("area: ${"%.2f".format(area(shape))}")
}
}
smart_cast_as.kt
kotlinc smart_cast_as.kt -include-runtime -d smart_cast_as.jar java -jar smart_cast_as.jar Int: 84 String (6 chars): KOTLIN List (3 items): [1, 2, 3] Boolean: true str: Hello num: null length: 5 area: 78.54 area: 12.00 area: 12.00
Common Mistakes
NG example 1: Smart cast does not work on var properties. The compiler cannot guarantee that a var has not been modified by another thread between the type check and the usage.
var value: Any = "item_a"
if (value is String) {
println(value.length) // Compile error: Smart cast to 'String' is impossible
}
The following example shows how this works in practice:
val name: Any = "item_b"
if (name is String) {
println(name.length) // 6
}
NG example 2: Using as (unsafe cast) on a value of unknown type throws a ClassCastException at runtime.
val obj: Any = 42 val s: String = obj as String // Throws ClassCastException
This produces the following output:
val obj: Any = 42 val s: String? = obj as? String println(s) // null
NG example 3: Casting with as after an is check is redundant — smart cast already applies inside the block.
val data: Any = "test"
if (data is String) {
val result = (data as String).uppercase() // as String is unnecessary
println(result)
}
The following example shows how this works in practice:
val data: Any = "test"
if (data is String) {
val result = data.uppercase() // No need for as String
println(result) // TEST
}
Notes
Smart cast is a compiler feature that automatically applies a cast after a type check. It works inside the block following an is check, and also on the right-hand side of && conditions. Note that smart cast does not apply to var properties or open properties in some cases.
as? is useful when converting external data or working with values of uncertain type. Because it returns null instead of throwing an exception on failure, you can safely provide a default value using the pattern as? Type ?: defaultValue.
For the basics of nullable types, see Nullable Type / ?. Operator. For using smart cast with sealed classes, see sealed class / sealed interface.
If you find any errors or copyright issues, please contact us.