What is the synthetic WhenMappings class that Kotlin sometimes generates, and which kind of `when` expression triggers it?
answer
- Enum when -> WhenMappings int[]
- $EnumSwitchMapping$0 maps ordinal -> dense index
- Avoids hard-coding unstable ordinals
- try/catch NoSuchFieldError per constant
- Enables fast tableswitch
basics
~20 sWhenMappings is a hidden helper class Kotlin creates when you switch over an enum (or sealed) in a when. It holds an int[] mapping each enum constant's ordinal to a small table index so the compiled switch is a fast tableswitch.
solid answer
~40 sWhen a `when` branches on an enum, the compiler can't emit a JVM `tableswitch` directly on `enum.ordinal` because ordinals are unstable across recompilation of the enum. So it generates a synthetic class `<EnclosingClass>$WhenMappings` containing a static `int[] $EnumSwitchMapping$0` initialized in a static block: it maps each used constant's `ordinal()` to a stable 1..N index, swallowing `NoSuchFieldError` per entry so a removed constant doesn't break the table. The `when` then does `tableswitch` on `WhenMappings.$EnumSwitchMapping$0[value.ordinal()]`. This shows up in Java completion/reflection and stack traces as a mysterious inner class. It's a performance optimization and an isolation mechanism so recompiling the enum alone doesn't silently shift behavior in dependent code. Multiple enum `when`s in one file share numbered fields ($0, $1, ...).
code
kotlin · 9 linesenum class Color { RED, GREEN, BLUE }
fun rgb(c: Color): Int = when (c) { // triggers WhenMappings
Color.RED -> 0xFF0000
Color.GREEN -> 0x00FF00
Color.BLUE -> 0x0000FF
}
// Generated: <File>Kt$WhenMappings.$EnumSwitchMapping$0 : int[]
// rgb() switches on $EnumSwitchMapping$0[c.ordinal()]go deeper
Recognizes WhenMappings as a compiler-generated helper for enum when and that it's not user API.
Explains the ordinal->dense-index int[] and that it enables a fast tableswitch.
Knows the NoSuchFieldError isolation, shared numbered fields per file, and reflection/stack-trace noise.
Reasons about binary compatibility guarantees: why separating ordinal from switch index protects against independent recompilation of enums across modules.
## The problem it solves A JVM `tableswitch` is a fast O(1) jump table indexed by an integer. The natural integer for an enum is `ordinal()` (its position, 0-based). But **ordinals are not part of the binary contract**: if you reorder or insert enum constants and recompile only the enum, any code that hard-coded ordinals would jump to the wrong branch. Kotlin avoids that trap. ## What gets generated For a `when` over an enum, the compiler emits a **synthetic class** `Owner$WhenMappings` with a static `int[]` field, conventionally named `$EnumSwitchMapping$0`: ```kotlin enum class State { NEW, RUNNING, DONE } fun label(s: State) = when (s) { State.NEW -> "new" State.RUNNING -> "go" State.DONE -> "end" } ``` Conceptually compiles to: ```java final class WhenKt$WhenMappings { static final int[] $EnumSwitchMapping$0 = new int[State.values().length]; static { try { $EnumSwitchMapping$0[State.NEW.ordinal()] = 1; } catch (NoSuchFieldError e) {} try { $EnumSwitchMapping$0[State.RUNNING.ordinal()] = 2; } catch (NoSuchFieldError e) {} try { $EnumSwitchMapping$0[State.DONE.ordinal()] = 3; } catch (NoSuchFieldError e) {} } } // label(): switch (WhenMappings.$EnumSwitchMapping$0[s.ordinal()]) { case 1: ...; case 2: ...; case 3: ...; } ``` - The array is **sized to the enum's length** and filled at class init. - Each assignment is wrapped in a `try/catch (NoSuchFieldError)` so that if a referenced constant was removed in a newer enum binary, the table simply leaves a 0 (falls to `else`) instead of crashing. - The mapped indices are **dense (1..N)** so the resulting `tableswitch` is compact regardless of the real ordinals. ## When it appears - Triggered by `when` on **enum** subjects (and similarly for some **sealed**-class exhaustive switches the compiler can table-ify). - Multiple such `when`s in the same file share one `WhenMappings` class with numbered fields `$EnumSwitchMapping$0`, `$1`, ... - A `when` over `String`/`Int` or arbitrary boolean conditions does NOT need it. ## Why a Java caller cares It is **synthetic** and an implementation detail: it appears in reflection (`getDeclaredClasses`), stack traces, and IDE 'go to declaration' as noise. You must never reference `$EnumSwitchMapping$0` directly; tooling that enumerates nested classes should skip synthetic ones.
- Why wrap each ordinal assignment in try/catch(NoSuchFieldError)?So that if the enum was recompiled with a constant removed, the static initializer for a dependent class doesn't throw; that constant just stays unmapped (index 0) and falls through to else.
- Does a `when` over a String produce WhenMappings?No. WhenMappings is specific to enum (and table-able sealed) subjects; String/Int whens use other strategies (hashCode switch / chained equals).
It's a coat-check ticket: instead of trusting the unstable cloakroom slot number (ordinal), Kotlin hands out its own stable ticket numbers so the switch always finds the right coat even if the cloakroom is rearranged.
saying these in an interview costs you the question
- Saying the switch is done directly on ordinal() (it isn't — that's the bug it avoids)
- Claiming WhenMappings appears for every when expression
- Thinking it's user-callable or stable API
- Not knowing why ordinals are unsafe across recompilation
- Confusing it with the enum's own $VALUES array