user1484819 user1484819 - 2 months ago 9
Scala Question

scala implicit method argument eliminate ambiguity

I don't quite understand following code:

object M {
implicit object AMarker
implicit object BMarker

def m(ints: Seq[Int])(implicit i: AMarker.type ): Unit = {
println(s"int seq $ints");
}

def m(strs: Seq[String])(implicit s: BMarker.type ): Unit = {
println(s"string seq $strs")
}
}

import M._

m(Seq(1, 2, 3))
m(Seq("a", "b", "c"))


If it weren't for the two markers, it will not compile because the two
m
methods have the same signature after type erasure.

However, I don't understand what is the "magic" that links
AMarker
to a
Seq[Int]
, and
BMarker
to
Seq[String]
.

More specificly, when I call
m(Seq("a", "b"))
, how does the compiler know it should use the implicit
BMarker
, and call the second
m
? Hasn't the
Seq
already been type erased?

Answer

To answer your question directly, no, the type erasure hasn't happened yet. Implicit search has to happen with full knowledge of types. To see how these methods look at runtime, you can run javap to see the compiled classes:

scala> :javap M -s
Compiled from "<console>"
public class M$ {
  public static final M$ MODULE$;
    Signature: LM$;
  public static {};
    Signature: ()V

  public void m(scala.collection.Seq<java.lang.Object>, M$AMarker$);
    Signature: (Lscala/collection/Seq;LM$AMarker$;)V

  public void m(scala.collection.Seq<java.lang.String>, M$BMarker$);
    Signature: (Lscala/collection/Seq;LM$BMarker$;)V

  public M$();
    Signature: ()V
}

So basically the compiler has made unambiguous runtime methods. It looks up the exact method during compile time, and essentially uses the implicit object to disambiguate.

Cool trick BTW! I haven't seen it used directly this way before.

Comments