Explain comma-grouped branches and `in`/`!in` range checks in `when`. What does comma between conditions mean?
answer
- Comma = OR within a branch
- `in`/`!in` -> contains()/!contains()
- Works with ranges, collections, custom contains
- Mix equality and `in` in one branch
- No AND via comma — use && in subjectless form
basics
~10 sA comma between conditions means OR: the branch matches if any listed value matches. in range checks membership and !in checks non-membership, working with ranges, collections, or anything defining contains.
solid answer
~40 sIn a subject `when`, you can list several conditions separated by commas — `1, 2, 3 -> ...` — which is an OR: the branch fires if the subject equals any of them. You can mix kinds in one branch, e.g. `0, in 10..20 -> ...`. The `in`/`!in` operators test containment: `in 1..10` (IntRange), `in listOf("a","b")` (any `Collection`), or any type defining `operator fun contains`. `!in` is the negation. These compile to `range.contains(x)` / `!range.contains(x)`. Comma grouping reduces duplication versus repeating branches and reads clearly. Note commas are OR within one branch — there's no AND syntax across comma-listed conditions; use `&&` inside a single boolean condition (typically in the subjectless form) for AND.
code
kotlin · 7 linesfun statusText(code: Int): String = when (code) {
200, 201, 204 -> "success"
in 300..399 -> "redirect"
in 400..499 -> "client error"
!in 100..599 -> "invalid"
else -> "server error"
}go deeper
Uses comma branches and basic in range checks for simple cases.
Explains comma = OR, !in negation, and that in desugars to contains for ranges and collections.
Notices allocation/performance of in collection literals and chooses Set vs Range deliberately.
Defines team conventions for readable membership checks and custom contains operators for domain types.
## Comma-grouped branches (OR) When a subject is present, multiple conditions on one branch are separated by commas and mean **logical OR**: ```kotlin when (key) { "ctrl", "alt", "shift" -> modifier() // matches any of the three else -> normalKey() } ``` The branch matches if the subject equals **any** listed value. This avoids repeating the same body across separate branches. ## `in` / `!in` containment The `in` operator checks **membership**; `!in` is its negation: ```kotlin when (n) { in 1..9 -> "single digit" // IntRange.contains(n) in 10..99 -> "two digits" !in 0..Int.MAX_VALUE -> "negative" // negation else -> "big" } ``` `in` works with anything that defines `operator fun contains`, including: - **Ranges**: `1..10`, `'a'..'z'`, `1..10 step 2` (via `IntProgression`). - **Collections**: `in listOf(...)`, `in setOf(...)`. - **Strings**: `'x' in "text"`, or substring via custom logic. - **Custom types** that define `contains`. `x in r` compiles to `r.contains(x)`, and `x !in r` to `!r.contains(x)`. ## Mixing kinds in one branch You can combine equality and containment with commas: ```kotlin when (code) { 0, in 200..299 -> "ok" // equals 0 OR in 200..299 in 400..499 -> "client error" else -> "other" } ``` ## OR only — no AND across commas Comma grouping is strictly OR. There is **no** comma-based AND. For AND logic, write a single boolean condition with `&&`, which usually means the subjectless form: `when { x > 0 && x < 10 -> ... }`. ## Why it matters Comma grouping and `in` keep branch logic declarative and dense without losing readability, and they let `when` express set/range membership that a constant-only `switch` cannot.
- Does `in listOf(...)` allocate a new list each call?Yes — that literal builds a new list per evaluation; hoist it to a constant/`val` if it's hot, or use a `Set` for O(1) membership.
- Can you express AND with commas?No — commas are OR only. Use a single `&&` condition (usually in the subjectless form).
saying these in an interview costs you the question
- Thinking comma means AND
- Believing `in` only works with numeric ranges
- Not knowing `in` desugars to `contains()`
- Allocating a fresh `listOf(...)` in a hot `in` check without noticing