Why won't this compile, and what does the error tell you about erasure? ```kotlin fun process(items: List<String>) {} fun process(items: List<Int>) {} ```
answer
- Both erase to process(List)
- Error: platform declaration clash / same JVM signature
- Fix with rename, @JvmName, or different erased types
- Array<Int> -> int[] does NOT clash
- Can't implement Comparable<A> and Comparable<B> together
basics
~10 sAfter the generic part is stripped away, both functions look identical to the JVM — both take a plain List. You can't have two functions that look the same, so it fails to compile.
solid answer
~30 sBecause type arguments are erased, both overloads collapse to the same JVM signature: `process(List)`. The compiler reports a **"platform declaration clash"** (same JVM signature `process(Ljava/util/List;)V`). Overload resolution on the JVM uses erased signatures, and `<String>` vs `<Int>` vanish, so the two declarations are indistinguishable to the linker. Fixes: rename one (`processStrings`/`processInts`), or use the `@JvmName` annotation to give one a distinct JVM method name, or change the parameter type so the erased signatures differ. This is a direct, everyday consequence of erasure that you cannot work around by being cleverer with generics — the information simply isn't in the bytecode signature.
code
kotlin · 7 lines// Clash: both erase to process(List)
// fun process(items: List<String>) {}
// fun process(items: List<Int>) {}
// Fix via @JvmName
@JvmName("processStrings") fun process(items: List<String>) {}
@JvmName("processInts") fun process(items: List<Int>) {}go deeper
Recognizes the snippet doesn't compile and that both lists look the same at runtime.
Names the platform-clash error and gives at least one correct fix (rename or @JvmName).
Explains the array-vs-collection erasure asymmetry and the same-supertype-twice restriction.
Designs APIs that avoid relying on type-argument overloading, weighing @JvmName ergonomics vs clear distinct names for interop.
## The clash Kotlin's **overloading** lets two functions share a name if their parameter types differ. But the JVM identifies methods by their **erased signature** — name plus erased parameter types. After erasure: - `process(List<String>)` → `process(List)` - `process(List<Int>)` → `process(List)` Both become `process(Ljava/util/List;)V`. They're the *same* method as far as the JVM is concerned, so the compiler refuses with a **"Platform declaration clash: The following declarations have the same JVM signature"** error. ## Why generics can't save you here There is no way to make `<String>` and `<Int>` survive into the signature on the JVM — that's the whole point of erasure. So no generic trick resolves it; you must change the *erased* picture or the name. ## Fixes ```kotlin // 1) Different names (clearest) fun processStrings(items: List<String>) {} fun processInts(items: List<Int>) {} // 2) @JvmName: distinct JVM method names, same Kotlin-call ergonomics @JvmName("processStrings") fun process(items: List<String>) {} @JvmName("processInts") fun process(items: List<Int>) {} // 3) Make erased signatures actually differ fun process(items: List<String>) {} fun process(items: Array<Int>) {} // Array<Int> erases to int[], a different signature ``` Note that **`Array<T>`** does *not* fully erase the same way collections do: `Array<Int>` becomes `int[]` and `Array<String>` becomes `String[]`, so array overloads with different element types *can* coexist. That asymmetry is itself a useful tell about how erasure treats arrays vs. generic classes. ## Related erasure-driven restrictions - You cannot have a class implement the same generic interface twice with different arguments (`Comparable<Foo>` and `Comparable<Bar>`) — the erased supertype clashes. - A `when`/`is` cannot branch on `List<String>` vs `List<Int>` for the same reason.
- Why does overloading `process(Array<String>)` and `process(Array<Int>)` compile when the `List` version doesn't?Arrays are reified on the JVM: `Array<String>` erases to `String[]` and `Array<Int>` to `int[]`, which are distinct signatures. Generic classes like `List` erase to the raw `List`, so they collide.
- Does `@JvmName` change how Kotlin callers invoke the function?No. Kotlin callers still call `process(...)` and the right overload is chosen at compile time; `@JvmName` only changes the *bytecode method name*, which is what de-collides the JVM signatures (and how Java sees them).
saying these in an interview costs you the question
- Claiming the two `List` overloads compile fine
- Suggesting a generic-variance trick to disambiguate erased signatures
- Not knowing `@JvmName` as a remedy
- Believing `Array<Int>` and `List<Int>` erase the same way
- Saying the error is a runtime failure rather than a compile error