What is a 'platform declaration clash' in Kotlin, and what commonly causes it?
answer
- Distinct in Kotlin, identical on JVM
- Type erasure collapses List<Int>/List<String> to List
- Descriptor = name + erased params
- @JvmName renames the bytecode method
- Kotlin call site unchanged
basics
~10 sIt is a compile error that happens when two Kotlin functions look different in Kotlin but turn into the exact same method on the JVM, so the JVM cannot tell them apart.
solid answer
~40 sA 'platform declaration clash' is a Kotlin compile-time error raised when two declarations are distinct in Kotlin source but compile to the same JVM method signature (same name + same erased parameter types + return type for some cases). The classic cause is generic type erasure: the JVM erases type arguments, so `fun f(x: List<Int>)` and `fun f(x: List<String>)` both become `f(List)`. Other causes include a property's generated getter colliding with a function, or two functions differing only by a return type the JVM does not consider part of the descriptor. The fix is to make one JVM signature distinct, usually by renaming the bytecode method via the `@JvmName("...")` annotation, which keeps the Kotlin-side names while giving each a unique JVM name.
code
kotlin · 9 lines// Compile error: platform declaration clash
fun sum(xs: List<Int>): Int = xs.sum()
fun sum(xs: List<Long>): Long = xs.sum()
// Fixed
@JvmName("sumInts")
fun sumI(xs: List<Int>): Int = xs.sum()
@JvmName("sumLongs")
fun sumL(xs: List<Long>): Long = xs.sum()go deeper
Can recognize the error message and name type erasure as the cause.
Applies @JvmName correctly and explains it only affects the JVM symbol, not Kotlin calls.
Explains JVM descriptors precisely and enumerates non-generic triggers (getter/function collisions).
Frames API design to avoid the clash entirely and weighs @JvmName vs distinct names for Java consumers.
## What the error means Kotlin compiles to JVM bytecode. On the JVM every method is identified by its **descriptor**: its name plus the (erased) types of its parameters. If two Kotlin declarations end up with the **same JVM descriptor**, the compiler reports a *platform declaration clash* — because the resulting `.class` file would contain two methods the JVM treats as identical, which is illegal. ## Why generics cause it: type erasure The JVM has no generics at runtime. Type arguments like `<Int>` or `<String>` are **erased** — `List<Int>` and `List<String>` both become the raw type `List` (technically `java.util.List`). So these two Kotlin functions: ```kotlin fun process(items: List<Int>) { } fun process(items: List<String>) { } ``` are perfectly valid and distinct in Kotlin, but both compile to the JVM method `process(java.util.List)`. Same descriptor -> clash. ## Other common triggers - A property generating a getter that collides with a same-named function (e.g. `val x` produces `getX()` colliding with `fun getX()`). - Functions differing only in return type after erasure. - An `Int`/`Long` etc. that boxes the same way is *not* a cause — primitives keep distinct descriptors. ## The fix: @JvmName The `@JvmName("...")` annotation renames the **generated bytecode method** without changing how you call it from Kotlin: ```kotlin @JvmName("processInts") fun process(items: List<Int>) { } @JvmName("processStrings") fun process(items: List<String>) { } ``` Now the JVM sees `processInts(List)` and `processStrings(List)` — distinct descriptors, no clash. From Kotlin you still call `process(...)`; from Java you call `processInts(...)` / `processStrings(...)`. ## Key terms - **Descriptor**: the JVM's identity for a method (name + param types). - **Erasure**: dropping generic type arguments at compile time. - **@JvmName**: renames the emitted JVM symbol for a function/getter/setter/file class.
- Does adding @JvmName change how Kotlin code calls the function?No. @JvmName only renames the emitted JVM method; Kotlin call sites resolve by the Kotlin name and are unaffected. Only Java callers see the new name.
Two contacts with different nicknames but the same phone number — your address book (Kotlin) shows two people, but the phone (JVM) can only dial one.
saying these in an interview costs you the question
- Claiming the JVM keeps generic type arguments at runtime
- Thinking the two functions are ambiguous to Kotlin's overload resolution (they are not)
- Suggesting you must rename the Kotlin-visible function name to fix it
- Confusing this with an unresolved-reference or overload-resolution error