When and why would you use @JvmName on an individual extension function (not the whole file), and what interop problem does it solve?
answer
- Generics erase → same JVM signature → clash
- @JvmName on fun renames one emitted method
- Kotlin call sites unaffected; Java uses new name
- Function-level cousin of @file:JvmName
- Also fixes Java-illegal/ugly names
basics
~20 sGeneric types erase at runtime, so two Kotlin extensions that look distinct can compile to the same JVM signature and clash. Putting @JvmName on one of them gives it a different method name so both can coexist.
solid answer
~40 sBecause of **type erasure**, generic extensions like `fun List<Int>.sum()` and `fun List<String>.sum()` both erase to `static X sum(List)` on the JVM — same signature, a 'platform declaration clash' compile error. Annotating a function with `@JvmName("sumInts")` renames just that emitted method so the JVM signatures differ, resolving the clash and giving Java a usable name. Kotlin call sites are unaffected (they still call `sum()`); only the JVM/Java-visible name changes. This is the function-level cousin of `@file:JvmName`: `@file:JvmName` renames the facade class, while `@JvmName` on a function renames one method. It is also used to expose a Kotlin name that would be illegal or ugly in Java.
code
kotlin · 6 linesfun List<Int>.sumIt(): Int = sum()
@JvmName("sumDoubles")
fun List<Double>.sumIt(): Double = sum()
// Without @JvmName: Platform declaration clash (both erase to sumIt(List))
// Kotlin: list.sumIt() Java: CollKt.sumDoubles(list)go deeper
Recognizes that two similar extensions can conflict and that an annotation can rename one.
Explains the clash but may be fuzzy on why erasure causes identical signatures.
Ties it precisely to erasure, shows @JvmName fixing the JVM signature while Kotlin call sites stay unchanged, and contrasts with @file:JvmName.
Manages these renames as part of a stable Java-facing API, anticipating erasure clashes in library design and documenting the Java method names.
## The erasure clash Kotlin keeps full generic types at compile time, but the JVM **erases** them. So these two perfectly valid Kotlin extensions: ```kotlin fun List<Int>.average(): Double = ... fun List<Double>.average(): Double = ... ``` both erase to `static double average(List $receiver)` — **identical JVM signatures**. The compiler reports a *"Platform declaration clash"* / *"conflicting overloads"* error because the JVM cannot hold two methods with the same signature. ## The fix: @JvmName on the function ```kotlin fun List<Int>.average(): Double = ... @JvmName("averageOfDoubles") fun List<Double>.average(): Double = ... ``` Now the second compiles to `static double averageOfDoubles(List)`. The signatures differ, so both coexist. ## Effect on call sites - **Kotlin** callers still write `myDoubles.average()`; resolution uses the *static Kotlin types*, so the right one is picked. The `@JvmName` is invisible to Kotlin. - **Java** callers must use the renamed method: `CollKt.averageOfDoubles(list)`. ## Other uses of @JvmName on a function - Expose a different Java name (e.g. the Kotlin name collides with a Java keyword or convention): `@JvmName("isEmpty")`. - Rename a getter/setter on a property. ## Relationship to @file:JvmName | Annotation | Renames | Target | |---|---|---| | `@file:JvmName("X")` | the facade **class** | whole file | | `@JvmName("x")` on fun | one **method** | single function | ## Pitfalls - `@JvmName` cannot be applied to `open`/`override` members that participate in virtual dispatch in some cases — but extensions are static, so this is usually fine. - Renaming changes the **Java-visible** binary contract; treat it as API. - Two same-signature extensions are still ambiguous to Java if both are reachable — give each a distinct `@JvmName` if Java must call both.
- Do Kotlin callers need to change when you add @JvmName to one of the clashing extensions?No. Kotlin resolution uses the static types and ignores @JvmName; only the Java-visible method name changes.
- What error do you get without @JvmName for two erasure-identical extensions?A 'Platform declaration clash' / conflicting JVM declarations compile error.
Two siblings with the same legal name confuse the post office (JVM); @JvmName gives one a nickname so mail (calls) reaches the right person.
saying these in an interview costs you the question
- Doesn't connect the clash to JVM type erasure
- Thinks @JvmName changes which extension Kotlin resolves
- Confuses @JvmName (one method) with @file:JvmName (the facade class)
- Believes the clash is a runtime, not compile-time, problem