Lesson 6 / 25
Type Checks, Casts and the Type Hierarchy
is, as, as? and Any, Unit, Nothing.
Checking and converting types
x is Type checks a type and smart casts x in the guarded scope; !is is the negation. x as Type is an unsafe cast that throws ClassCastException on failure, while x as? Type is a safe cast returning null. At the top of the hierarchy is Any (and Any? for nullable values). Functions with no useful return value return Unit. Nothing is the type of expressions that never complete normally, such as throw or TODO(), which is why ?: throw ... type-checks. Numbers do not convert implicitly: use toLong(), toDouble() and similar.
Safe casts and explicit conversion
No implicit widening.
fun lengthOf(value: Any): Int {
if (value is String) return value.length // smart cast
val list = value as? List<*> ?: return -1 // safe cast + elvis
return list.size
}
fun fail(message: String): Nothing = throw IllegalStateException(message)
fun main() {
val small: Int = 42
val big: Long = small.toLong() // explicit conversion required
val ratio = small / 5.0 // Int / Double gives Double
val config: String = System.getenv("APP_MODE") ?: fail("APP_MODE not set")
}Prefer is over as
An is check followed by a smart cast is safer and clearer than an unchecked as. Reach for as? when a failed cast is a normal outcome.
Quick check: What does `value as? String` return if `value` is an Int?
- An empty string
- It throws ClassCastException
- The Int converted to text
- null
Answer
null — as? is the safe cast.