E120: Double Definition
E120: Double Definition (이중 정의)
두 정의가 소거(erasure) 후에 같은 이름과 타입을 가져서 충돌할 때 나오는 에러예요.
본문
JVM은 타입 소거(type erasure) 때문에 런타임에 제네릭 파라미터를 제거해요. 그래서 서로 다른 제네릭 시그니처를 가진 메서드가 런타임에는 같은 시그니처를 갖게 되어 충돌이 생길 수 있어요.
예시
class Example:
def process(list: List[Int]): Unit = ()
def process(list: List[String]): Unit = ()
에러 메시지
-- [E120] Naming Error: example.scala:3:6 --------------------------------------
3 | def process(list: List[String]): Unit = ()
| ^
|Conflicting definitions:
|def process(list: List[Int]): Unit in class Example at line 2 and
|def process(list: List[String]): Unit in class Example at line 3
|have the same type (list: List): Unit after erasure.
|
|Consider adding a @targetName annotation to one of the conflicting definitions
|for disambiguation.
|-----------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| As part of the Scala compilation pipeline every type is reduced to its erased
| (runtime) form. In this phase, among other transformations, generic parameters
| disappear and separate parameter-list boundaries are flattened.
|
| For example, both `f[T](x: T)(y: String): Unit` and `f(x: Any, z: String): Unit`
| erase to the same runtime signature `f(x: Object, y: String): Unit`. Note that
| parameter names are irrelevant.
|
| In your code the two declarations
|
| def process(list: List[Int]): Unit
| def process(list: List[String]): Unit
|
| erase to the identical signature
|
| (list: List): Unit
|
| so the compiler cannot keep both: the generated bytecode symbols would collide.
|
| To fix this error, you must disambiguate the two definitions by doing one of the following:
|
| 1. Rename one of the definitions.
| 2. Keep the same names in source but give one definition a distinct
| bytecode-level name via `@targetName`; for example:
|
| @targetName("process_2")
| def process(list: List[String]): Unit
|
| Choose the `@targetName` argument carefully: it is the name that will be used
| when calling the method externally, so it should be unique and descriptive.
-----------------------------------------------------------------------------
해결 방법
메서드 이름을 다르게 하거나, @targetName으로 서로 다른 바이트코드 이름을 주거나, 하나의 제네릭 메서드로 합치면 돼요.
// Use different method names
class Example:
def processInts(list: List[Int]): Unit = ()
def processStrings(list: List[String]): Unit = ()
// Or use @targetName to give them different bytecode names
import scala.annotation.targetName
class Example:
def process(list: List[Int]): Unit = ()
@targetName("processStrings")
def process(list: List[String]): Unit = ()
// Or combine into a single generic method
class Example:
def process[T](list: List[T]): Unit = ()
더 알아보기
@targetName어노테이션에 대한 자세한 내용은 Scala 3 Reference의@targetName문서를 참고해요.