Bird
Raised Fist0
Kotlinprogramming~15 mins

When with ranges and types in Kotlin - Deep Dive

Choose your learning style10 modes available
Overview - When with ranges and types
What is it?
In Kotlin, the 'when' expression is a powerful tool to check a value against multiple conditions. It can test if a value falls within a range or matches a specific type. This lets you write clear and concise code that handles different cases without many if-else statements. It works like a smart switch that can understand numbers, types, and more.
Why it matters
Without 'when' expressions that handle ranges and types, code becomes long and hard to read because you'd need many if-else checks. This makes programs slower to write and harder to maintain. Using 'when' with ranges and types helps you write safer, cleaner, and more understandable code, which reduces bugs and saves time.
Where it fits
Before learning 'when' with ranges and types, you should know basic Kotlin syntax, variables, and simple 'when' expressions. After this, you can explore advanced pattern matching, sealed classes, and smart casts to handle complex data structures.
Mental Model
Core Idea
The 'when' expression matches a value against ranges or types to choose the right action clearly and efficiently.
Think of it like...
Imagine a mail sorter who checks each letter: if the address is in a certain neighborhood (range), it goes to one bin; if the letter is a special type like a package or postcard, it goes to another. The sorter quickly decides where each item belongs based on these rules.
┌───────────────┐
│   when(value) │
├───────────────┤
│ in 1..10 -> A │
│ in 11..20 -> B│
│ is String -> C│
│ else -> D     │
└───────────────┘
Build-Up - 7 Steps
1
FoundationBasic when expression usage
🤔
Concept: Learn how to use 'when' as a replacement for simple if-else chains.
val x = 5 when (x) { 1 -> println("One") 2 -> println("Two") else -> println("Other") }
Result
Prints: One, Two, or Other depending on x.
Understanding 'when' as a cleaner alternative to multiple if-else statements simplifies decision-making in code.
2
FoundationRanges in Kotlin basics
🤔
Concept: Understand what ranges are and how to create them.
val range = 1..5 println(3 in range) // true println(6 in range) // false
Result
Prints true then false, showing how ranges check if a number fits inside.
Knowing ranges lets you check if values fall between limits easily, which is common in many programs.
3
IntermediateUsing when with numeric ranges
🤔Before reading on: do you think 'when' can check if a number is inside a range directly? Commit to yes or no.
Concept: Learn how to use 'when' to test if a number falls within a range.
val score = 85 when (score) { in 90..100 -> println("Excellent") in 75..89 -> println("Good") in 0..74 -> println("Needs Improvement") else -> println("Invalid score") }
Result
Prints "Good" because 85 is in 75..89.
Using ranges inside 'when' makes checking intervals clear and concise, avoiding nested ifs.
4
IntermediateUsing when with type checks
🤔Before reading on: do you think 'when' can check the type of a variable without explicit casting? Commit to yes or no.
Concept: Discover how 'when' can check the type of a variable and smart cast it automatically.
fun describe(obj: Any) = when (obj) { is String -> "String of length ${obj.length}" is Int -> "Integer with value $obj" else -> "Unknown type" } println(describe("Hello")) println(describe(42))
Result
Prints: String of length 5 Integer with value 42
Type checking in 'when' lets you handle different data types safely and use their properties without extra casts.
5
IntermediateCombining ranges and types in when
🤔
Concept: Learn to mix range and type conditions in one 'when' expression.
fun check(value: Any) = when (value) { in 1..10 -> "Number in 1 to 10" is String -> "String with length ${value.length}" !is Int -> "Not an integer" else -> "Other" } println(check(5)) println(check("Hi")) println(check(20))
Result
Prints: Number in 1 to 10 String with length 2 Other
Mixing ranges and types in 'when' allows flexible and readable branching for many data forms.
6
AdvancedSmart casts and null safety in when
🤔Before reading on: do you think 'when' automatically handles null values safely when checking types? Commit to yes or no.
Concept: Understand how 'when' works with nullable types and smart casts to avoid errors.
fun process(input: Any?) = when (input) { null -> "Null value" is String -> "String length ${input.length}" is Int -> "Integer $input" else -> "Unknown" } println(process(null)) println(process("Kotlin"))
Result
Prints: Null value String length 6
Knowing how 'when' handles null and smart casts prevents common runtime errors and improves code safety.
7
ExpertPerformance and evaluation order in when
🤔Before reading on: do you think 'when' evaluates all conditions even after a match is found? Commit to yes or no.
Concept: Learn how Kotlin evaluates 'when' conditions and how this affects performance and side effects.
val x = 5 when { x > 0 -> println("Positive") x < 0 -> println("Negative") else -> println("Zero") } // Conditions are checked top to bottom, stops at first true.
Result
Prints "Positive" and skips other checks.
Understanding evaluation order helps write efficient 'when' expressions and avoid unintended side effects.
Under the Hood
The 'when' expression compiles into a series of conditional checks. For ranges, it uses the 'contains' method to test membership. For type checks, Kotlin uses the 'is' operator, which performs a runtime type check and enables smart casting within the matched branch. The evaluation stops as soon as a matching condition is found, making it efficient.
Why designed this way?
Kotlin designed 'when' to be a flexible, readable alternative to switch and if-else chains. Supporting ranges and types directly reduces boilerplate and errors. The smart cast feature was added to improve safety and reduce explicit casting, making code cleaner and less error-prone.
┌───────────────┐
│   when(value) │
├───────────────┤
│ Check first   │
│ condition:    │
│ - if range    │
│   call contains│
│ - if type     │
│   call is     │
├───────────────┤
│ If true ->    │
│ execute block │
│ else -> next  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does 'when' check all conditions even after finding a match? Commit to yes or no.
Common Belief:People often think 'when' evaluates every condition before deciding.
Tap to reveal reality
Reality:'when' stops checking as soon as it finds the first matching condition.
Why it matters:Believing otherwise can lead to inefficient code or unexpected side effects if conditions have function calls.
Quick: Can 'when' check if a value is inside a range using '==' operator? Commit to yes or no.
Common Belief:Some think you can write 'when (x) { x == 1..10 -> ... }' to check ranges.
Tap to reveal reality
Reality:You must use 'in' keyword, not '==', to check if a value is inside a range.
Why it matters:Using '==' with ranges causes compile errors or wrong logic, confusing beginners.
Quick: Does 'when' automatically cast a variable to a type outside the matching branch? Commit to yes or no.
Common Belief:Many believe smart casts apply everywhere after a type check in 'when'.
Tap to reveal reality
Reality:Smart casts only apply inside the branch where the type is confirmed, not outside.
Why it matters:Misunderstanding this causes compile errors or unsafe casts when accessing properties.
Quick: Can 'when' check multiple types in one branch using commas? Commit to yes or no.
Common Belief:Some think you can write 'is String, is Int -> ...' in one branch.
Tap to reveal reality
Reality:Kotlin requires separate branches for each type; commas are not allowed for multiple type checks in one branch.
Why it matters:Trying to combine types this way causes syntax errors and confusion.
Expert Zone
1
The order of conditions in 'when' matters deeply; placing broader ranges or types first can shadow later cases.
2
Smart casts in 'when' rely on Kotlin's flow analysis, which can fail if variables are mutable or accessed concurrently.
3
Using 'when' without an argument (like 'when { condition -> ... }') allows complex boolean expressions but loses some type smart casts.
When NOT to use
Avoid 'when' for very complex nested conditions better handled by polymorphism or sealed classes. For performance-critical tight loops, prefer direct if-else to avoid overhead. Also, do not use 'when' for side-effect-heavy conditions that must all run.
Production Patterns
In production, 'when' with ranges and types is used for input validation, parsing user data, and handling API responses. It often appears in combination with sealed classes for exhaustive checks, ensuring all cases are handled at compile time.
Connections
Pattern Matching in Functional Programming
'when' builds on the idea of pattern matching found in languages like Haskell or Scala.
Understanding 'when' as pattern matching helps grasp how Kotlin simplifies branching by matching values, types, and ranges in one construct.
Type Systems in Programming Languages
'when' uses Kotlin's strong type system and smart casts to safely check and use types.
Knowing how type systems work clarifies why 'when' can safely access properties after type checks without explicit casts.
Decision Trees in Machine Learning
'when' expressions resemble decision trees where each condition splits the path.
Seeing 'when' as a decision tree helps understand evaluation order and efficiency in branching logic.
Common Pitfalls
#1Using '==' instead of 'in' to check ranges in 'when'.
Wrong approach:when (x) { x == 1..10 -> println("In range") else -> println("Out of range") }
Correct approach:when (x) { in 1..10 -> println("In range") else -> println("Out of range") }
Root cause:Confusing equality check with membership test; '==' compares objects, 'in' checks range inclusion.
#2Expecting smart cast outside the 'when' branch after type check.
Wrong approach:val obj: Any = "Hello" when (obj) { is String -> println(obj.length) } println(obj.length) // Error
Correct approach:val obj: Any = "Hello" when (obj) { is String -> println(obj.length) } // Outside 'when', obj is still Any, so cast needed
Root cause:Smart casts only apply inside the branch where type is confirmed, not outside.
#3Placing a broad range condition before a narrower one, causing unreachable code.
Wrong approach:when (x) { in 1..100 -> println("Between 1 and 100") in 1..10 -> println("Between 1 and 10") // Unreachable else -> println("Other") }
Correct approach:when (x) { in 1..10 -> println("Between 1 and 10") in 11..100 -> println("Between 11 and 100") else -> println("Other") }
Root cause:Order of conditions matters; broader ranges first can shadow narrower ones.
Key Takeaways
'when' expressions in Kotlin let you match values against ranges and types clearly and efficiently.
Using 'in' checks membership in ranges, while 'is' checks the type safely with smart casts inside branches.
The order of conditions in 'when' affects which branch runs and can cause unreachable code if not careful.
'when' stops checking conditions after the first match, making it efficient and predictable.
Understanding smart casts and null safety in 'when' prevents common runtime errors and improves code clarity.

Practice

(1/5)
1. What does the when expression in Kotlin do when used with ranges like in 1..5?
easy
A. It throws an error if the value is outside the range.
B. It creates a new range from 1 to 5.
C. It assigns the value to the range variable.
D. It checks if the value falls within the specified range.

Solution

  1. Step 1: Understand the when with range syntax

    The syntax in 1..5 inside when checks if the value is between 1 and 5 inclusive.
  2. Step 2: Interpret the check

    If the value is inside the range, the corresponding branch executes; otherwise, it moves to the next case.
  3. Final Answer:

    It checks if the value falls within the specified range. -> Option D
  4. Quick Check:

    when with in checks range membership [OK]
Hint: Remember: in means inside the range [OK]
Common Mistakes:
  • Thinking in creates a range instead of checking membership
  • Confusing in with assignment
  • Assuming it throws errors for out-of-range values
2. Which of the following is the correct syntax to check if a variable x is NOT in the range 10 to 20 using when in Kotlin?
easy
A. when(x) { !in 10..20 -> "Outside" }
B. when(x) { not in 10..20 -> "Outside" }
C. when(x) { x !in 10..20 -> "Outside" }
D. when(x) { outside 10..20 -> "Outside" }

Solution

  1. Step 1: Recall the correct negation syntax in when

    In Kotlin, !in is used to check if a value is NOT in a range.
  2. Step 2: Match the syntax with options

    when(x) { !in 10..20 -> "Outside" } uses !in 10..20 correctly inside when. Other options use invalid keywords or syntax.
  3. Final Answer:

    when(x) { !in 10..20 -> "Outside" } -> Option A
  4. Quick Check:

    Use !in to check exclusion from range [OK]
Hint: Use !in to say NOT in range [OK]
Common Mistakes:
  • Using 'not in' instead of '!in'
  • Writing variable name inside when case
  • Using undefined keywords like 'outside'
3. What will be the output of this Kotlin code?
val x: Any = 42
val result = when (x) {
  is Int -> "Integer"
  in 1..10 -> "Small number"
  else -> "Unknown"
}
println(result)
medium
A. Small number
B. Unknown
C. Integer
D. Compilation error

Solution

  1. Step 1: Check the type of x

    Variable x is of type Any but holds the value 42, which is an Int.
  2. Step 2: Evaluate when branches in order

    The first branch checks is Int, which is true, so it returns "Integer". The second branch is not checked because the first matched.
  3. Final Answer:

    Integer -> Option C
  4. Quick Check:

    when matches first true branch [OK]
Hint: Type checks with is come before range checks [OK]
Common Mistakes:
  • Assuming range check runs before type check
  • Confusing value 42 as outside 1..10
  • Thinking when checks all branches
4. Identify the error in this Kotlin when expression:
val y: Any = "Hello"
val output = when (y) {
  in 1..5 -> "Number"
  is String -> "Text"
  else -> "Other"
}
println(output)
medium
A. Cannot use in with Any type without casting
B. The is String check should come before the range check
C. Missing break statements in when
D. No error, code runs fine

Solution

  1. Step 1: Analyze the in 1..5 check on Any

    The variable y is of type Any. The in operator with ranges requires a comparable type like Int. Using in 1..5 on Any causes a type mismatch error.
  2. Step 2: Check order of branches and syntax

    The is String check is valid but unreachable if the first branch errors. Also, when in Kotlin does not require break.
  3. Final Answer:

    Cannot use in with Any type without casting -> Option A
  4. Quick Check:

    Range checks need compatible types [OK]
Hint: Check variable type before using in with ranges [OK]
Common Mistakes:
  • Ignoring type mismatch for in operator
  • Thinking when needs break
  • Assuming order of branches causes error
5. You want to write a Kotlin when expression that returns:
- "Small Int" if the value is an Int between 1 and 10 inclusive,
- "Large Int" if the value is an Int greater than 10,
- "String" if the value is a String,
- "Other" for anything else.

Which of the following when expressions correctly implements this?
hard
A. when (v) { in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" }
B. when (v) { is Int -> if (v in 1..10) "Small Int" else "Large Int" is String -> "String" else -> "Other" }
C. when (v) { is Int in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" }
D. when (v) { is Int && v in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" }

Solution

  1. Step 1: Understand the conditions needed

    We need to check if v is an Int and then check its value range for "Small Int" or "Large Int". Also check if v is a String.
  2. Step 2: Analyze each option's correctness

    when (v) { in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" } incorrectly uses in 1..10 without checking type first, causing errors if v is not Int. when (v) { is Int in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" } uses invalid syntax is Int in 1..10. when (v) { is Int && v in 1..10 -> "Small Int" is Int -> "Large Int" is String -> "String" else -> "Other" } uses invalid syntax is Int && v in 1..10 inside when. when (v) { is Int -> if (v in 1..10) "Small Int" else "Large Int" is String -> "String" else -> "Other" } correctly checks type first, then uses an if inside the branch to distinguish ranges.
  3. Final Answer:

    Option B correctly implements the logic. -> Option B
  4. Quick Check:

    Use nested if inside when for complex conditions [OK]
Hint: Check type first, then range inside branch with if [OK]
Common Mistakes:
  • Using invalid syntax combining is and in
  • Not checking type before range
  • Trying to use logical operators directly in when cases
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard