Type Checks & Smart Casts (is, as)
Type checks let you ask what kind of value you hold at runtime with the is operator, and smart casts then let the compiler treat that value as its real type automatically — no manual casting needed.
Learn Type Checks & Smart Casts (is, as) in our free Kotlin course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Kotlin course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
You'll also learn the unsafe cast as , the safe cast as? , and how when combines with is .
What You'll Learn in This Lesson
1️⃣ Checking Types with is / !is
The is operator returns a Boolean telling you whether a value is of a given type at runtime; !is negates it. This is how you safely inspect a value whose static type is broad, like Any .
2️⃣ Smart Casts
Here's the magic: once an is check succeeds, the compiler smart-casts the value inside that block, so you can use the narrowed type's members directly — no as required. It works because the compiler can prove the value didn't change.
3️⃣ Explicit Casts: as vs as?
When you must cast explicitly, choose carefully. The unsafe cast as throws a ClassCastException if the type is wrong. The safe cast as? returns null instead — pair it with the Elvis operator for a clean fallback.
The most idiomatic pattern of all is when combined with is — each branch smart-casts automatically:
Your turn. Fill in the ___ blanks, then run and compare.
Write a when (x) {' '} that labels a value by its type.
📋 Quick Reference — Type Checks & Casts
Practice quiz
What does the is operator return?
- The casted value
- A new object
- A Boolean telling whether the value is of that type
- Always null
Answer: A Boolean telling whether the value is of that type. is is a runtime type check that evaluates to a Boolean.
What does !is mean?
- A bitwise operation
- An assignment
- Force-cast the value
- The negation of an is check
Answer: The negation of an is check. !is is true when the value is NOT of the given type.
After if (x is String) succeeds, what does the compiler do inside the block?
- Smart-casts x to String automatically
- Throws an exception
- Forces you to write (x as String)
- Sets x to null
Answer: Smart-casts x to String automatically. A smart cast lets you use String members directly with no manual cast.
What happens with val n = x as Int when x is actually a String?
- It returns null
- It throws a ClassCastException
- It returns 0
- It compiles to false
Answer: It throws a ClassCastException. as is an unsafe cast; a wrong type throws ClassCastException at runtime.
What does the safe cast as? do when the cast cannot succeed?
- Throws an exception
- Crashes the program
- Returns null instead of throwing
- Returns the original value
Answer: Returns null instead of throwing. as? yields null when the value is not of the target type.
Which expression is the safest explicit cast with a fallback?
- x as Int
- (x !is Int)
- x is Int
- (x as? Int) ?: 0
Answer: (x as? Int) ?: 0. Combine the safe cast as? with the Elvis operator for a default.
In a when (x) block, what does an is branch give you?
- A smart cast inside that branch
- A compile error
- A null value
- An infinite loop
Answer: A smart cast inside that branch. Each is branch smart-casts x to that type for use in the branch.
What is Any in Kotlin's type system?
- A nullable-only type
- The root of the non-null type hierarchy
- A keyword for casting
- A collection type
Answer: The root of the non-null type hierarchy. Every non-null type is a subtype of Any, like Object in Java.
Why prefer an is check over an explicit as cast?
- as is faster
- is only works on numbers
- An is check is both a test and a safe smart cast, so it is safer and clearer
- as is required for smart casts
Answer: An is check is both a test and a safe smart cast, so it is safer and clearer. An is check tests and smart-casts, avoiding the risk of as throwing.
Smart casts apply most reliably to which kind of variable?
- A reassignable var
- A global mutable property
- A lateinit field
- An immutable val (or a parameter)
Answer: An immutable val (or a parameter). The compiler can prove an immutable val did not change between check and use.