How I discovered the DummyImplicit (in Scala)

Antoine Doeraene
4 min readDec 9, 2019

Recently we stumbled on a problem that at first glance looks particularly simple: overload a method for a `List[String]` and a `List[Int]`. One could expect that simply writing

def foo(ls: List[String]): Unit = ???
def foo(ls: List[Int]): Unit = ???

would do the trick, the same way as we would do

def foo(s: String): Unit = ???
def foo(j: Int): Unit = ???

As much as the latter will work like a charm, the former will gratify you with the following compile-time error:

[error] both methods
[error] def foo(ls: List[Int]): Unit at line 11 and
[error] def foo(ls: List[String]): Unit at line 12
[error] have same type after erasure: (ls: List)Unit
[error] def foo(ls: List[String]): Unit = ???
[error] ^

In the following, we’re going to explain why this happens, give the solution and explain why the solution works.

Why it fails

Actually, the compile error message says it all, given that we understand the words it uses. It says that the two functions will have the same type after “erasure”, namely a function from `List` to `Unit`. Where are the types `Int` and `String`, then? Well, that is exactly what type erasure is. At compile type, all type parameters are removed and they are no more available at runtime.

That means that the program will not know which method to call with the objects it receives, and that is what it is telling us.

The exact same phenomenon appears when you try to pattern match on a type parameter, like so:

val ls: List[Int] = ???
ls match {
case ls: List[Int] => ???
case ls: List[String] => ???
}

It’s a little “worse” in this case since you only have warnings, like so:

fruitless type test: a value of type List[Int] cannot also be a List[String] (the underlying of List[String]) (but still might match its erasure)
[warn] case ls: List[String] => ???
[warn] ^
[warn] /[...]/src/main/scala/main/Main.scala:15:30: unreachable code
[warn] case ls: List[String] => ???
[warn] ^

The second warning says that you’ll never enter that piece of code since type erasure will always make the `case ls: List[Int]` to match before. The first warning is irrelevant to our situation, and you would have something different by defining `val ls: List[Any] = ???`.

Antoine Doeraene

Mathematician, Scala enthusiast, father of two.