def merge[X](list1: Option[List[X]], list2: Option[List[X]]): Option[List[X]]
def merge[X](list1: Option[List[X]], elem: Option[X]): Option[List[X]]
The compiler says that these two functions have same type after erasure
def merge[X](list1: Option[List[X]],list2: Option[List[X]]): Option[List[X]] at line 122 and
def merge[X](list1: Option[List[X]],elem: Option[X]): Option[List[X]] at line 131
have same type after erasure: (list1: Option, list2: Option)Option
Why does the Option[List[X]]
and Option[X]
become same after erasure?
How can I make them different?
Why does the
Option[List[X]]
andOption[X]
become same after erasure?
Because the generic type parameter of Option[...]
is erased (so both X
and List[X]
are erased) so both methods will have the same signature.
How can I make them different?
One approach - adding dummy implicit parameter to one of the methods so they have different signatures:
def merge[X](list1: Option[List[X]], list2: Option[List[X]]): String = "1"
def merge[X](list1: Option[List[X]], elem: Option[X])(implicit d: DummyImplicit): String = "2"
println(merge(Some(List(1)), Some(List(2)))) // 1
println(merge(Some(List(1)), Some(2))) // 2
For Scala 3 (thanks to @Gaël J for pointing that out) @targetName
annotation can be used to resolve the ambiguity:
import scala.annotation.targetName
def merge[X](list1: Option[List[X]], list2: Option[List[X]]): String = "1"
@targetName("merge_element")
def merge[X](list1: Option[List[X]], elem: Option[X]): String = "2"
println(merge(Some(List(1)), Some(List(2)))) // 1
println(merge(Some(List(1)), Some(2))) // 2