7

I see the term "implicit evidence" in many SOF and blog posts, related to runtime retention of type information. I searched the net but have not found any simple explanation what "implicit evidence" is.

This concept comes up, for example, here.

EDIT:

A comment to Travis' nice answer:

From Predef.scala:

  sealed abstract class <:<[-From, +To] extends (From => To) 
      with Serializable

  private[this] final val singleton_<:< = 
      new <:<[Any,Any] { def apply(x: Any): Any = x }

  implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]

I don't see how the unzip's "asPair" function parameter can be derived from singleton_<:<.asInstanceOf[A <:< A]. Could someone please comment on this?

jhegedus
  • 20,244
  • 16
  • 99
  • 167
  • 3
    +1, by the way—this could use some links but it's a perfectly reasonable question and I don't see why it's getting votes to close. – Travis Brown Feb 17 '14 at 02:23
  • Perhaps because the original version was asking several related questions like : What is it precisely? Why is it needed? When is it used? How is it created ? Who creates it? Where is it documented? – jhegedus Feb 17 '14 at 02:28
  • 1
    Suppose your list is of type `List[(Int, String)]`. For `unzip` you need an implicit `(Int, String) => (A, B)` for some `A` and `B`. Implicit search finds that `conforms` will produce a `(Int, String) <:< (Int, String)`, which is a subtype of `(Int, String) => (Int, String)`, and so it plugs that in. – Travis Brown Feb 17 '14 at 07:56
  • 1
    For newcomers to Scala, it may be worth mentioning that `implicit` is a language keyword, whereas calling the parameter "evidence" is just a convention, and other names are often used - as you can see from the `asPair" example in the answer below. – DNA Feb 17 '14 at 15:01

1 Answers1

12

A good example in the standard library is the definition of unzip on e.g. a List[A]:

def unzip[A1, A2](implicit asPair: (A) ⇒ (A1, A2)): (List[A1], List[A2])

The goal is to allow the following to compile:

val (ks, vs) = List('a -> 1, 'b -> 2, 'c -> 3).unzip

But not this:

val (ks, vs) = List(1, 2, 3).unzip

This is accomplished via an implicit argument that witnesses that the type of the list can be viewed as a pair. In the example above this evidence is provided by Predef.conforms, which for any type A will implicitly provide an instance of A <:< A, which is a subtype of A => A. The instance provided by conforms will of course just be the identity function.

If you look at the definition of unzip, you'll see how the evidence is used in this case:

def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = {
    val b1 = genericBuilder[A1]
    val b2 = genericBuilder[A2]
    for (xy <- sequential) {
      val (x, y) = asPair(xy)
      b1 += x
      b2 += y
    }
    (b1.result, b2.result)
  }

I.e., it's used to deconstruct the items in the sequence. Remember that this method is defined on any List[A], so writing plain old val (x, y) = xy wouldn't compile.

Other applications of implicit evidence may have different goals (some quite complex) and may use the implicit evidence in different ways (it's not necessarily just a function), but the basic pattern is generally going to be more or less the same as what you see with unzip.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680