scalagenericstypesimpliciterasure

How is Implicit finding the correct method to be invoked with generics when types are erased?


In my code below, I have a function test that takes in a object of type magnet and I have two implicit methods converting List[Int] to magnet and the other converting List[String] to magnet.

If JVM is supposed to loose the types in generics due to type erasure at run time, In my below code both the methods fromListInt and fromListString will look like List[Any] right? Because when I name both functions with same name I got the error error: double definition: suggesting that both List[Int] and List[String] are considered same.

how are the correct implicit methods found in this case when I pass List(0) and List("0") ?

scala> trait magnet {
     | def printSomething: Unit
     | }
defined trait magnet

scala> object magnet {
     | implicit def fromListInt(future: List[Int]): magnet = {
     | new magnet { def printSomething: Unit = println("test int") }
     | }
     | implicit def fromListString(future: List[String]): magnet = {
     | new magnet { def printSomething: Unit = println("test string") }
     | }
     | }
defined object magnet
scala> def test(in: magnet): Unit = {
     | in.printSomething
     | }
test: (in: magnet)Unit

scala> import magnet._
import magnet._

scala> test(List(0))
test int

scala> test(List("0"))
test string


Solution

  • Implicits are resolved at compile time, not at runtime. At compile time, nothing has been erased. Full type information is available to the compiler.

    In a REPL, every time you type a line of code, you are compiling it before you are running it. test(List(0)) gets converted by the compiler to something like test(fromListInt(List(0))), and that what is compiled, and so that is the behavior you see. test(List("0")) gets converted by the compiler to something like test(fromListString(List("0"))), and so that is the behavior you see there.